Skip to content

Add Slack as a TaskSpawner source (MVP)#1002

Open
jkahuja wants to merge 4 commits intokelos-dev:mainfrom
datagravity-ai:feat/slack-source-mvp
Open

Add Slack as a TaskSpawner source (MVP)#1002
jkahuja wants to merge 4 commits intokelos-dev:mainfrom
datagravity-ai:feat/slack-source-mvp

Conversation

@jkahuja
Copy link
Copy Markdown

@jkahuja jkahuja commented Apr 16, 2026

What type of PR is this?

/kind feature

What this PR does / why we need it:

Adds slack as a new source type in the TaskSpawner When struct, enabling
task 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:

  • Slack API type with 2 fields: channels and mentionUserIDs
  • Centralized kelos-slack-server binary that connects to Slack via Socket Mode
    (outbound WebSocket — no ingress required) and routes messages to matching
    TaskSpawners
  • Message filtering: channel restrictions and @-mention requirements
  • Thread context fetching for follow-up messages within a Slack thread
  • Helm templates: Deployment, ServiceAccount, RBAC (ClusterRole/ClusterRoleBinding)
  • TaskSpawner controller updated to treat Slack as webhook-based (no spawner
    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 prompt
  • allowedUsers — restrict which Slack user IDs can trigger tasks
  • excludeCommands — negative routing to prevent a spawner from firing on messages intended for another spawner

Which 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?

Add Slack as a TaskSpawner source with a centralized kelos-slack-server that connects via Socket Mode and routes messages to matching agents.

Summary by cubic

Adds Slack as a TaskSpawner source via a centralized kelos-slack-server that 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

    • New API: spec.when.slack with channels and triggers (RE2 patterns, OR semantics, per-trigger mentionOptional); bot mention is implicit by default. CRD validations include channel ID patterning and trigger pattern with MinLength=1.
    • Central kelos-slack-server: leader-elected Socket Mode listener (no ingress), Helm Deployment/ServiceAccount/RBAC; least-privilege RBAC to create tasks only.
    • Routing: channel filter; @mention required unless a trigger sets mentionOptional; slash commands bypass mention/trigger; thread replies include fetched context.
    • Controller treats Slack like webhooks (no per-spawner Deployment); adds github.com/slack-go/slack.
  • Migration

    • Create a secret with SLACK_BOT_TOKEN and SLACK_APP_TOKEN; set .Values.slackServer.secretName, enable with .Values.slackServer.enabled=true, and configure the image if needed.
    • Invite the bot to the Slack channels to monitor.
    • Add when.slack to TaskSpawners. Use {} to fire on any bot mention, or set channels and triggers to narrow matching.

Written for commit 21a196b. Summary will update on new commits. Review in cubic

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>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 16, 2026

Choose a reason for hiding this comment

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

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>
Fix with Cubic

Comment thread internal/manifests/charts/kelos/templates/rbac.yaml
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>
@gjkim42
Copy link
Copy Markdown
Collaborator

gjkim42 commented Apr 27, 2026

/kelos api-review

kelos-bot[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Collaborator

@gjkim42 gjkim42 left a comment

Choose a reason for hiding this comment

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

API Design Review

Verdict: COMMENT
Scope: api/v1alpha1/taskspawner_types.goSlack 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.

Copy link
Copy Markdown
Collaborator

@gjkim42 gjkim42 left a comment

Choose a reason for hiding this comment

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

reviewed from an API perspective, which is a minimal and expandable API.
What do you think?

@knechtionscoding
Copy link
Copy Markdown
Contributor

@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?

@gjkim42
Copy link
Copy Markdown
Collaborator

gjkim42 commented Apr 27, 2026

Then how about adding a field for make it optional?

mentionOptional *bool to SlackTrigger?

@knechtionscoding
Copy link
Copy Markdown
Contributor

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>
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

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.

Comment thread api/v1alpha1/taskspawner_types.go
Prevents empty regex patterns that would match every message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jkahuja
Copy link
Copy Markdown
Author

jkahuja commented Apr 28, 2026

@gjkim42 thanks for your feedback! I addressed your comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature needs-actor needs-priority needs-triage release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants