Skip to content

feat(api): Add generic webhook source for arbitrary event-driven task spawning - #902

Merged
gjkim42 merged 1 commit into
kelos-dev:mainfrom
datagravity-ai:feat/generic-webhook
Apr 16, 2026
Merged

gjkim42 merged 1 commit into
kelos-dev:mainfrom
datagravity-ai:feat/generic-webhook

Conversation

@knechtionscoding

@knechtionscoding knechtionscoding commented Apr 3, 2026 •

Copy link
Copy Markdown
Contributor

What type of PR is this?

/kind feature

What this PR does / why we need it:

Adds a generic webhook source type (spec.when.webhook) to TaskSpawner that accepts arbitrary HTTP POST payloads with JSON bodies and maps them to task template variables via configurable JSONPath expressions. This enables integration with any webhook-capable system (Notion, Sentry, Drata, Salesforce, Aikido, etc.) without requiring Kelos-side code changes for each new integration.

Key design decisions:

  • Path-based routing: Each source gets its own path (/webhook/<source>) and derives its HMAC secret from the <SOURCE>_WEBHOOK_SECRET environment variable (e.g., /webhook/notion → NOTION_WEBHOOK_SECRET)
  • JSONPath field extraction: fieldMapping maps JSONPath expressions to template variables available in promptTemplate and branch
  • AND-semantics filters: Filters support exact match and regex, all must match for a delivery to trigger a task
  • Plugs into existing infrastructure: Reuses the kelos-webhook-server with --source generic rather than creating per-spawner Deployments
  • No workspaceRef required: Generic webhook spawners can optionally omit workspaceRef since they may not be git-repo-driven
  • Helm chart support: Adds webhookServer.sources.generic with envFrom-based multi-secret injection so all per-source secrets come from a single Secret resource

Which issue(s) this PR is related to:

Fixes #687

Special notes for your reviewer:

  • The generic source uses envFrom in the helm chart (not valueFrom) since users will have multiple <SOURCE>_WEBHOOK_SECRET keys in one Secret
  • The SignaturePrefix field defaults to "sha256=" but can be set to "" for providers that send raw hex digests (e.g., Linear-style)
  • Filter semantics are AND (all must match), unlike GitHub/Linear webhook filters which use OR. AND is more intuitive for generic payloads since there are no event-type scopes. OR can be achieved by creating multiple TaskSpawners
  • The ingress/gateway routes use /webhook/ as a catch-all prefix for generic, which is placed after the more specific /webhook/github and /webhook/linear rules
  • Added github.com/PaesslerAG/jsonpath dependency for JSONPath evaluation

Does this PR introduce a user-facing change?

feat: Add generic webhook source type for TaskSpawner that accepts arbitrary HTTP POST payloads and maps JSON fields to task template variables via JSONPath expressions, enabling integration with any webhook-capable system without Kelos-side code changes.

Summary by cubic

Adds a generic webhook source to TaskSpawner to spawn tasks from any JSON POST at /webhook/<source> using JSONPath field mapping and AND-filters, with id-based idempotency when fieldMapping.id is set (fallback to body‑hash). Implements #687.

  • New Features

    • Generic webhooks: POST /webhook/<source> routes to the generic handler; delivery IDs use fieldMapping.id when present, else body‑hash.
    • JSONPath mapping: fieldMapping populates template vars (id required); ID, Title, Body, URL default to empty; .Payload always available.
    • Filters: AND semantics with exact or regex matches; spawners match on source.
    • Server/Charts: kelos-webhook-server --source=generic serves under /webhook/; adds generic Deployment/Service and /webhook/ routes to ingress/gateway; controller treats generic as webhook‑driven; CRD validations added.
    • Dependencies: add github.com/PaesslerAG/jsonpath.
  • Migration

    • Helm: enable webhookServer.sources.generic.enabled, optionally set webhookServer.sources.generic.secretName for env injection.
    • Define a TaskSpawner with spec.when.webhook (source, fieldMapping with id, optional filters), then send POSTs to /webhook/<source>.

Written for commit f960432. Summary will update on new commits.

@knechtionscoding
knechtionscoding marked this pull request as ready for review April 3, 2026 15:29

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 17 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yaml">

<violation number="1" location="internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yaml:1011">
P2: CRD says fieldMapping must include an `id` key, but schema doesn’t enforce it; generic webhook handling will accept missing `id` and leave parsed.ID empty, contradicting the documented requirement.</violation>
</file>

<file name="api/v1alpha1/taskspawner_types.go">

<violation number="1" location="api/v1alpha1/taskspawner_types.go:488">
P2: XValidation does not enforce the documented “set exactly one” requirement for value/pattern; filters with neither field set pass validation.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread api/v1alpha1/taskspawner_types.go Resolved
@gjkim42

gjkim42 commented Apr 4, 2026

Copy link
Copy Markdown
Collaborator

/kelos review

@kelos-bot

kelos-bot Bot commented Apr 4, 2026 •

Copy link
Copy Markdown
Contributor

🤖 Kelos Task Status

Task kelos-reviewer-902 has failed. ❌

@kelos-bot kelos-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Kelos Reviewer Agent @gjkim42

Review Summary

Verdict: REQUEST CHANGES
Scope: Adds generic webhook source type to TaskSpawner with path-based routing, JSONPath field extraction, HMAC signature validation, and Helm chart support

Findings

Correctness

  • internal/webhook/generic_filter.go:39 / internal/webhook/handler.go:482 — Shared Fields map leaks state across spawner iterations (blocking)
    ExtractFields adds keys to parsed.Generic.Fields but never clears the map between spawner iterations. In processWebhook (line 357–414), the loop calls matchesSpawner → ExtractFields for each spawner. If Spawner A has fieldMapping: {id: "$.a.id", custom_a: "$.a.val"} and Spawner B has fieldMapping: {id: "$.b.id"}, after processing Spawner A the Fields map contains {id: "...", custom_a: "..."}. When Spawner B runs, it overwrites id but leaves custom_a from Spawner A. Then createTask → ExtractGenericWorkItem for Spawner B includes the stale custom_a as a template variable.
    Fix: Reset Fields to a fresh map at the start of ExtractFields.

  • internal/webhook/handler.go:563-581 — getGenericWebhookConfig lists ALL TaskSpawners on every request (non-blocking)
    Every incoming generic webhook triggers a client.List of all TaskSpawners to determine signature/delivery headers, in addition to the existing getMatchingSpawners List call further down. This doubles the API server load per webhook delivery. Consider combining these into a single List, or caching the config per source with a short TTL.

  • internal/webhook/handler.go:576 — getGenericWebhookConfig returns first-match only
    If multiple TaskSpawners listen to the same source with different SignatureHeader or SignaturePrefix values, only the first match's config is used for validation. The second spawner's signature config is silently ignored. Worth documenting in the CRD field comments.

Tests

  • Test coverage is comprehensive: parsing, field extraction, filters (AND semantics, exact/regex, nested fields, numeric/boolean coercion), path extraction, signature validation (with/without prefix), HTTP handler tests for matching, non-matching, wrong source, idempotency, and hyphenated source names. Well done.
  • make verify passes — generated files (deepcopy, CRD YAML, install-crd.yaml) are up to date.
  • make test was still compiling from scratch in this container environment; no failures observed at the time of review.

Cubic's prior review — rebuttal

The two P2 violations flagged by cubic are both incorrect:

  1. "CRD says fieldMapping must include an id key, but schema doesn't enforce it" — Wrong. The CRD YAML (taskspawner-crd.yaml:1084) contains an x-kubernetes-validation rule: 'id' in self.fieldMapping. This enforces the requirement at the schema level.

  2. "XValidation does not enforce the 'set exactly one' requirement for value/pattern" — Wrong. The rule has(self.value) != (has(self.pattern) && size(self.pattern) > 0) uses XOR semantics that correctly rejects both-omitted and both-set cases.

Security

  • No hardcoded secrets — per-source secrets loaded from env vars at runtime
  • HMAC-SHA256 signature validation with timing-safe comparison via existing validateHMACSignature
  • Payload size limit (10 MB) inherited from existing handler
  • Source name from URL path is safe: os.Getenv treats the string literally, no injection risk
  • Optional no-secret mode (skip validation) is clearly logged — appropriate for sources that don't support signing

Conventions

  • Logging messages start with capital letters, no trailing punctuation ✓
  • Generated files included and match make update output ✓
  • PR description follows template with all sections filled ✓
  • workspaceRef validation rule intentionally excludes webhook source — correct per design (generic webhooks may not be git-repo-driven)

Suggestions (optional)

  • internal/webhook/generic_filter.go:68 — regexp.MatchString recompiles the regex on every filter evaluation. For high-throughput sources, consider compiling once. Not blocking for v1 but worth a TODO.
  • Consider adding validation that prevents two spawners from claiming the same source name with conflicting SignatureHeader/SignaturePrefix configurations.
  • Minor: extractSourceFromPath rejects paths with >3 segments but returns the generic "Missing source" message. A more descriptive error could help debugging.

/kelos needs-input

Comment thread internal/webhook/generic_filter.go Resolved
Comment thread internal/webhook/handler.go Resolved
@knechtionscoding

Copy link
Copy Markdown
Contributor Author

@gjkim42 I have implemented review notes and suggestions. Let me know if there's anything else :)

@gjkim42 gjkim42 self-assigned this Apr 6, 2026
@gjkim42 gjkim42 added priority/important-soon triage-accepted kind/api Categorizes issue or PR as related to API changes kind/feature Categorizes issue or PR as related to a new feature labels Apr 6, 2026
@github-actions github-actions Bot removed needs-triage needs-kind Indicates an issue or PR lacks a kind/* label needs-priority labels Apr 6, 2026
@gjkim42

gjkim42 commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

Will take a look. Thanks for the PR!

@knechtionscoding

Copy link
Copy Markdown
Contributor Author

@gjkim42 bump :)

@gjkim42

gjkim42 commented Apr 11, 2026

Copy link
Copy Markdown
Collaborator

I am generally positive about the feature. My only concern is API is hard to fix, so I'd like to find the best way to design it.

// Must be lowercase alphanumeric with optional hyphens.
// +kubebuilder:validation:Required
// +kubebuilder:validation:Pattern=`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`
Source string `json:"source"`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source should be unique in cluster scope, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The source is unique in the cluster, but we aren't spawning a new webhook server per source (at least not currently).

The current implementation spawns a single GenericWebhook taskSpawner that then listens for everything that isn't routed to one of our specific handlers. This means on the taskSpawner you have to declare which source you care to listen too.

For example, if you are listening to both notion and salesforce on the taskspawners for those you need to declare what source you care about.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gjkim42 Any concerns here? Otherwise I'll rework the other thread and push for final review

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a validation that prevents duplicate sources?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because it isn't declared anywhere as a universal.

You are allowed to have multiple task spawners listening to the same source.

And on the webhook server side it just sees the path and reads for the secret. There's no ability for duplication anywhere.

Because once deployed you can send to webhook/test, webhook/notion, webhook/drata without any further configuration on the server side.

Once the generic source is deployed it then just checks for an existing taskSpawner with source that matches what it received.

So there's nothing to ensure isn't duplicated.

Comment thread api/v1alpha1/taskspawner_types.go Resolved
Comment thread api/v1alpha1/taskspawner_types.go Resolved
@knechtionscoding

Copy link
Copy Markdown
Contributor Author

@gjkim42 Updated based on review comments and ensured verify passes.

Comment thread internal/webhook/handler.go Resolved
Comment thread internal/webhook/generic_filter.go Resolved
… spawning

Adds a new `webhook` source type to TaskSpawner that accepts arbitrary
HTTP POST payloads and maps them to task template variables via JSONPath
expressions. This enables integration with any webhook-capable system
(Notion, Sentry, Drata, etc.) without Kelos-side code changes.

Key design:
- Path-based routing: /webhook/<source> determines both the URL and
  the HMAC secret env var (<SOURCE>_WEBHOOK_SECRET)
- Configurable JSONPath field extraction via fieldMapping
- AND-semantics filters with exact match and regex support
- Plugs into the existing kelos-webhook-server with --source generic
- No workspaceRef required for generic webhook spawners
- Helm chart adds generic source with envFrom-based multi-secret support
- If a secret doesn't exist accept json in

Implements kelos-dev#687
@gjkim42
gjkim42 enabled auto-merge April 16, 2026 10:47
@gjkim42
gjkim42 disabled auto-merge April 16, 2026 11:18
@gjkim42
gjkim42 merged commit f076a8c into kelos-dev:main Apr 16, 2026
34 checks passed
@knechtionscoding
knechtionscoding deleted the feat/generic-webhook branch April 17, 2026 15:26
kelos-bot Bot pushed a commit that referenced this pull request Apr 27, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
kelos-bot Bot pushed a commit that referenced this pull request May 1, 2026
Adds five conventions distilled from recent PR reviews and applies them
across AGENTS.md, the shared and worker AgentConfigs, and the reviewer
prompts.

1. Never use os.Getenv() for secrets as Go flag defaults (PR #971)
   — flag prints defaults in --help output, leaking secret values.

2. Fail fast on invalid configuration (PR #971) — do not silently fall
   back to unauthenticated/degraded behavior when credentials or config
   are missing.

3. Keep API surfaces minimal (PR #902) — only fields immediately needed,
   no speculative additions; API is hard to change once shipped.

4. Docs must match implementation, not aspiration (PRs #1035, #1056) —
   describe only what the code actually does; verify enforcement before
   documenting a contract.

5. TaskSpawner conventions (PRs #965, #974):
   - Prefer webhook-based triggers over poll-based.
   - {{.Branch}} is empty for issue-only events; use the
     {{if .Branch}}{{.Branch}}{{else}}main{{end}} fallback form.
   - issue_comment fires for both issues and PRs; design prompts to
     detect and handle both contexts.
   - Do not include manual PR branch checkout instructions — Kelos
     checks out the PR branch automatically.

Also fixes the kelos-reviewer TaskSpawner branch field to use the safe
fallback form (was using bare {{.Branch}}, which is empty for issue
events; flagged P2 in PR #786 review).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kelos-bot Bot pushed a commit that referenced this pull request May 3, 2026
Adds five conventions distilled from recent PR reviews and applies them
across AGENTS.md, the shared and worker AgentConfigs, and the reviewer
prompts.

1. Never use os.Getenv() for secrets as Go flag defaults (PR #971)
   — flag prints defaults in --help output, leaking secret values.

2. Fail fast on invalid configuration (PR #971) — do not silently fall
   back to unauthenticated/degraded behavior when credentials or config
   are missing.

3. Keep API surfaces minimal (PR #902) — only fields immediately needed,
   no speculative additions; API is hard to change once shipped.

4. Docs must match implementation, not aspiration (PRs #1035, #1056) —
   describe only what the code actually does; verify enforcement before
   documenting a contract.

5. TaskSpawner conventions (PRs #965, #974):
   - Prefer webhook-based triggers over poll-based.
   - {{.Branch}} is empty for issue-only events; use the
     {{if .Branch}}{{.Branch}}{{else}}main{{end}} fallback form.
   - issue_comment fires for both issues and PRs; design prompts to
     detect and handle both contexts.
   - Do not include manual PR branch checkout instructions — Kelos
     checks out the PR branch automatically.

Also fixes the kelos-reviewer TaskSpawner branch field to use the safe
fallback form (was using bare {{.Branch}}, which is empty for issue
events; flagged P2 in PR #786 review).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kelos-bot Bot pushed a commit that referenced this pull request May 8, 2026
Distills thirteen recurring conventions from recent PR review feedback and
propagates them across AGENTS.md, the shared and worker AgentConfigs, and
the reviewer prompts. All changes are backed by specific PR review findings.

1. Never use os.Getenv() for secrets as Go flag defaults — PR #971 P1
   (cmd/kelos-webhook-server, cmd/ghproxy leaked GITHUB_TOKEN via --help).
2. Fail fast on invalid configuration — PR #971 multiple P1/P2 (silent
   degradation when GitHub App credentials or token resolvers failed).
3. Keep API surfaces minimal — PR #902 (maintainer asked repeatedly to
   defer speculative fields and ship the minimum viable API).
4. API changes must preserve backward compatibility — PR #1058 (BodyContains
   scalar->array would break in-cluster manifests; resolved by deprecating
   the old field rather than tightening validation).
5. Docs must match implementation, not aspiration — PRs #1035, #1056, #1082
   (docs claimed enforcement that the code never performed).
6. TaskSpawner conventions — PRs #965, #974 (webhook over poll, empty
   .Branch for issue events, dual issue/PR context, no manual checkout).
7. Don't use Gomega's global Expect() inside Eventually polling blocks —
   PR #1084 (transient API errors short-circuited the poller).
8. /kind cleanup for self-development/-only PRs — PR #1100 P2 (agent
   classified by problem nature; rule is to classify by file location).
9. CLI error messages must name the resource — PR #1101 P2 (errors.New
   ("task failed") loses the name when batched).
10. Test the happy path, not only early-return guards — PR #1096 (both
    new tests covered only the no-op branches because production code
    lacked a posting seam; rule now requires adding the seam).
11. Avoid vacuous substring assertions in printer tests — PR #1106 P2
    (a "sentry" check passed because the fixture's Name was "sentry-fixer").
12. Keep CRD enum docstrings consistent with the Enum marker — PR #1081 P2
    (commentOn godoc said "empty matches both" but the marker rejected "").
13. Qualify cross-CRD field references with the owning kind in docs —
    PR #1077 P2 (Workspace section cited bare podOverrides.env without
    noting the field lives on Task.spec).

Also: kelos-reviewer branch field uses the safe with-index fallback form,
kelos-squash-commits gates the issue_comment trigger to PullRequest comments
(preventing /kelos squash-commits typed on a plain issue from running
git push --force-with-lease against an empty branch fallback), and the
README's .Branch description matches runtime behavior.
kelos-bot Bot pushed a commit that referenced this pull request May 10, 2026
Distills thirteen recurring conventions from recent PR review feedback and
propagates them across AGENTS.md, the shared and worker AgentConfigs, and
the reviewer prompts. All changes are backed by specific PR review findings.

1. Never use os.Getenv() for secrets as Go flag defaults — PR #971 P1
   (cmd/kelos-webhook-server, cmd/ghproxy leaked GITHUB_TOKEN via --help).
2. Fail fast on invalid configuration — PR #971 multiple P1/P2 (silent
   degradation when GitHub App credentials or token resolvers failed).
3. Keep API surfaces minimal — PR #902 (maintainer asked repeatedly to
   defer speculative fields and ship the minimum viable API).
4. API changes must preserve backward compatibility — PR #1058 (BodyContains
   scalar->array would break in-cluster manifests; resolved by deprecating
   the old field rather than tightening validation).
5. Docs must match implementation, not aspiration — PRs #1035, #1056, #1082
   (docs claimed enforcement that the code never performed).
6. TaskSpawner conventions — PRs #965, #974 (webhook over poll, empty
   .Branch for issue events, dual issue/PR context, no manual checkout).
7. Don't use Gomega's global Expect() inside Eventually polling blocks —
   PR #1084 (transient API errors short-circuited the poller).
8. /kind cleanup for self-development/-only PRs — PR #1100 P2 (agent
   classified by problem nature; rule is to classify by file location).
9. CLI error messages must name the resource — PR #1101 P2 (errors.New
   ("task failed") loses the name when batched).
10. Test the happy path, not only early-return guards — PR #1096 (both
    new tests covered only the no-op branches because production code
    lacked a posting seam; rule now requires adding the seam).
11. Avoid vacuous substring assertions in printer tests — PR #1106 P2
    (a "sentry" check passed because the fixture's Name was "sentry-fixer").
12. Keep CRD enum docstrings consistent with the Enum marker — PR #1081 P2
    (commentOn godoc said "empty matches both" but the marker rejected "").
13. Qualify cross-CRD field references with the owning kind in docs —
    PR #1077 P2 (Workspace section cited bare podOverrides.env without
    noting the field lives on Task.spec).

Also: kelos-reviewer branch field uses the safe with-index fallback form,
kelos-squash-commits gates the issue_comment trigger to PullRequest comments
(preventing /kelos squash-commits typed on a plain issue from running
git push --force-with-lease against an empty branch fallback), the
kelos-squash-commits branch field uses the same with-index fallback form
for defensive consistency with the documented convention, and the README's
.Branch description matches runtime behavior (PR head branch or pushed
branch; empty for issue events).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kelos-bot Bot pushed a commit that referenced this pull request May 17, 2026
Propagates eleven recurring conventions, distilled from prior PR review
feedback, across AGENTS.md, the shared and worker AgentConfigs, and the
reviewer prompts. Also fixes two existing self-development spawner
configurations that were flagged in adjacent reviews.

Conventions added to AGENTS.md, agentconfig.yaml, and kelos-workers.yaml:

1. Never use os.Getenv() for secrets as Go flag defaults — PR #971 P1
   (cmd/kelos-webhook-server, cmd/ghproxy leaked GITHUB_TOKEN via --help).
2. Fail fast on invalid configuration — PR #971 multiple P1/P2 (silent
   degradation when GitHub App credentials or token resolvers failed).
3. Keep API surfaces minimal — PR #902 (maintainer asked repeatedly to
   defer speculative fields and ship the minimum viable API).
4. API changes must preserve backward compatibility — PR #1058
   (BodyContains scalar->array would break in-cluster manifests; resolved
   by deprecating the old field rather than tightening validation).
5. Docs must match implementation, not aspiration — PRs #1035, #1056,
   #1082 (docs claimed enforcement that the code never performed).
6. Don't use Gomega's global Expect() inside Eventually polling blocks —
   PR #1084 (transient API errors short-circuited the poller).
7. CLI error messages must name the resource — PR #1101 P2
   (errors.New("task failed") loses the name when batched).
8. Test the happy path, not only early-return guards — PR #1096 (tests
   covered only the no-op branches because production code lacked a
   posting seam; rule now requires adding the seam).
9. Avoid vacuous substring assertions in printer tests — PR #1106 P2
   (a "sentry" check passed because the fixture's Name was "sentry-fixer").
10. Keep CRD enum docstrings consistent with the Enum marker — PR #1081
    P2 (commentOn godoc said "empty matches both" but the marker rejected "").
11. Qualify cross-CRD field references with the owning kind in docs —
    PR #1077 P2 (Workspace section cited bare podOverrides.env without
    noting the field lives on Task.spec).

Reviewer/api-reviewer checklists gain matching items so kelos-reviewer
and kelos-api-reviewer flag these patterns on future PRs.

Other fixes in the same sweep:

- kelos-reviewer.spec.taskTemplate.branch uses the safe
  '{{with index . "Branch"}}{{.}}{{else}}main{{end}}' fallback form so
  a /kelos review typed on a plain issue lands on main rather than an
  empty branch.
- kelos-squash-commits gates the issue_comment trigger to
  commentOn: PullRequest and uses the same with-index fallback for the
  branch field — /kelos squash-commits typed on a plain issue would
  otherwise fire the spawner with empty {{.Branch}} and the prompt then
  runs git push --force-with-lease.
- self-development/README.md template-variable table corrected from
  "Usually PR head branch" to "PR head branch or pushed branch; empty
  for issue events" to match runtime behavior, and the bodyContains
  example was updated to bodyPattern to match the spawner configs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
ok-to-test — f9604324 Deployed Apr 16, 2026 by knechtionscoding via fork-e2e / e2e-with-environment #112
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/api Categorizes issue or PR as related to API changes kind/feature Categorizes issue or PR as related to a new feature needs-actor priority/important-soon release-note triage-accepted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integration: Add generic webhook source type to TaskSpawner for universal event-driven task triggering

2 participants