Add Slack as a TaskSpawner source (MVP)#1002
Conversation
Adds a new `slack` source type to TaskSpawner that triggers task creation from Slack messages via Socket Mode. A centralized kelos-slack-server connects to Slack via an outbound WebSocket (no ingress required) and routes messages to matching TaskSpawners based on channel restrictions and @-mention requirements. Includes Helm templates for deploying the slack server (Deployment, ServiceAccount, RBAC) and updates the TaskSpawner controller to treat Slack sources as webhook-based (no spawner Deployment created). Reporting (posting status updates back to Slack threads) is deferred to a follow-up PR. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
There was a problem hiding this comment.
2 issues found across 21 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="cmd/kelos-slack-server/Dockerfile">
<violation number="1" location="cmd/kelos-slack-server/Dockerfile:1">
P2: Base image is not pinned to an immutable digest/version, so builds can drift over time.</violation>
</file>
<file name="internal/manifests/charts/kelos/templates/rbac.yaml">
<violation number="1" location="internal/manifests/charts/kelos/templates/rbac.yaml:289">
P2: Slack server RBAC grants unnecessary Task update/watch access even though the Slack handler only creates Tasks.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| @@ -0,0 +1,5 @@ | |||
| FROM gcr.io/distroless/static:nonroot | |||
There was a problem hiding this comment.
P2: Base image is not pinned to an immutable digest/version, so builds can drift over time.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmd/kelos-slack-server/Dockerfile, line 1:
<comment>Base image is not pinned to an immutable digest/version, so builds can drift over time.</comment>
<file context>
@@ -0,0 +1,5 @@
+FROM gcr.io/distroless/static:nonroot
+WORKDIR /
+COPY bin/kelos-slack-server .
</file context>
The slack handler only creates Tasks — the update and watch verbs were left over from the reporting loop which is not included in this MVP. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
/kelos api-review |
There was a problem hiding this comment.
API Design Review
Verdict: COMMENT
Scope: api/v1alpha1/taskspawner_types.go — Slack source
Desired shape
type Slack struct {
// The bot must be invited to each channel; this is a post-delivery
// filter, not a privacy scope. Empty = every invited channel.
// +optional
// +kubebuilder:validation:MaxItems=64
// +kubebuilder:validation:items:Pattern=`^[CG][A-Z0-9]{8,}$`
Channels []string `json:"channels,omitempty"`
// Bot mention is implicitly required. Pattern triggers add a regex
// AND'd with the mention. Multiple triggers OR. Empty = every bot
// mention fires.
// +optional
// +kubebuilder:validation:MaxItems=8
Triggers []SlackTrigger `json:"triggers,omitempty"`
}
type SlackTrigger struct {
// Go RE2 regex against message text. Unanchored.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MaxLength=256
Pattern string `json:"pattern"`
}Smallest valid spawner:
spec:
when:
slack: {}fires on any bot mention in any invited channel.
|
@gjkim42 I like the idea of it listening for itself automatically. But it is also helpful to not require a specific mention, if you want to trigger on some other text then an @ specifically? Might not be worth adding right now? |
|
Then how about adding a field for make it optional? mentionOptional *bool to SlackTrigger? |
|
I think that is reasonable |
…er patterns
Reshape the Slack source API per review feedback:
- Remove MentionUserIDs field; bot mention is now implicit (the handler
knows its own user ID from Slack auth)
- Add Triggers []SlackTrigger with RE2 regex patterns (OR semantics)
- Add MentionOptional *bool per trigger to fire on pattern alone
- Add kubebuilder validation markers (MaxItems, Pattern, MaxLength)
Simplest valid config is now `slack: {}` which fires on any bot mention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 8 files (changes from recent commits).
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="api/v1alpha1/taskspawner_types.go">
<violation number="1" location="api/v1alpha1/taskspawner_types.go:528">
P1: Slack trigger Pattern field lacks MinLength validation, allowing an empty regex pattern that matches every message and can cause runaway task spawning</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Prevents empty regex patterns that would match every message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@gjkim42 thanks for your feedback! I addressed your comment |
What type of PR is this?
/kind feature
What this PR does / why we need it:
Adds
slackas a new source type in the TaskSpawnerWhenstruct, enablingtask creation from Slack messages. This is the minimum viable implementation
for API review — it includes the core triggering flow but defers status
reporting (posting updates back to Slack threads) to a follow-up PR.
What's included:
SlackAPI type with 2 fields:channelsandmentionUserIDskelos-slack-serverbinary that connects to Slack via Socket Mode(outbound WebSocket — no ingress required) and routes messages to matching
TaskSpawners
Deployment created)
What's NOT included:
This MVP does not post any status updates back to Slack — no "accepted",
"done", or "failed" messages appear in the thread. If barebones reporting
(plain text phase transitions) is desired in this PR, that's a small addition
(~170 lines). Otherwise, full rich reporting (Block Kit, live progress,
agent response rendering) will come in a follow-up PR.
Additional filtering coming in follow-up PRs (already implemented in datagravity-ai#75):
triggerCommand— slash command or message prefix (e.g., "/kelos", "!fix") that triggers task creation and is stripped from the promptallowedUsers— restrict which Slack user IDs can trigger tasksexcludeCommands— negative routing to prevent a spawner from firing on messages intended for another spawnerWhich issue(s) this PR is related to:
Towards #932
Special notes for your reviewer:
This is carved out of a larger implementation (datagravity-ai#75) to keep the
API review focused.
Does this PR introduce a user-facing change?
Summary by cubic
Adds Slack as a TaskSpawner source via a centralized
kelos-slack-serverthat listens with Socket Mode to spawn tasks from Slack messages. This includes channel filtering, implicit @bot mention, optional regex triggers, and slash commands; posting status back to Slack will come later.New Features
spec.when.slackwithchannelsandtriggers(RE2 patterns, OR semantics, per-triggermentionOptional); bot mention is implicit by default. CRD validations include channel ID patterning and triggerpatternwith MinLength=1.kelos-slack-server: leader-elected Socket Mode listener (no ingress), Helm Deployment/ServiceAccount/RBAC; least-privilege RBAC to createtasksonly.mentionOptional; slash commands bypass mention/trigger; thread replies include fetched context.github.com/slack-go/slack.Migration
SLACK_BOT_TOKENandSLACK_APP_TOKEN; set.Values.slackServer.secretName, enable with.Values.slackServer.enabled=true, and configure the image if needed.when.slackto TaskSpawners. Use{}to fire on any bot mention, or setchannelsandtriggersto narrow matching.Written for commit 21a196b. Summary will update on new commits. Review in cubic