Skip to content

Add Slack connector - #1

Merged
sadfun merged 20 commits into
mainfrom
agent/port-slack-connector
Aug 6, 2026
Merged

sadfun merged 20 commits into
mainfrom
agent/port-slack-connector

Conversation

@sadfun

@sadfun sadfun commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Ports the Slack connector from sadfun/telex#1 into Wirebot while retaining the original PR ancestry.

  • Socket Mode connector for DMs, mention-gated channel threads, files, approvals, commands, scheduled notifications, and interactive Codex settings
  • Slack-only or dual Telegram + Slack configuration
  • Wirebot naming and /wirebot commands
  • Adapted to Wirebot's Bun build, immutable Ubuntu image, current Codex bridge APIs, and shared provider contracts

Review follow-ups

Three independent review passes covered correctness/security, architecture/simplification, and integration/operations. The resulting fixes include:

  • approval cancellation and stale-button cleanup
  • deferred-login attachment lifetime and cleanup
  • persisted scheduled-result context recovery after restart
  • paginated, newest-biased Slack thread context
  • fail-closed workspace authorization with shared display-name caching
  • sensitive message/reasoning bodies removed from default info logs
  • truthful Socket Mode readiness logging
  • shared command/help metadata and smaller common progress/lifecycle plumbing
  • bounded file downloads, attachment cleanup, and safe Slack-host validation
  • upstream-only GitHub CLI/auth bootstrap removed from the runtime image

Validation

Before the repository's temporary connector tests were removed at maintainer request:

  • bun run check
  • 65/65 temporary tests passed
  • bun run compile
  • compiled binary smoke test (0.1.0)
  • full ARM64 Docker image build
  • container entrypoint/version smoke test

The final no-tests tree was then revalidated with bun run check, bun run compile, the compiled binary smoke test, entrypoint syntax validation, a full ARM64 Docker rebuild, the container version smoke test, and git diff --check. The test files, package script, CI test step, and README test claims are intentionally absent pending the project-wide testing framework.

nocell and others added 19 commits July 28, 2026 11:10
Bridge Codex into Slack alongside Telegram: DMs stream progress by
editing a single message, channel mentions open threaded conversations,
approvals arrive as buttons, files flow both ways, and a /telex slash
command carries the bridge commands. Enabled by setting SLACK_BOT_TOKEN,
SLACK_APP_TOKEN, and SLACK_ALLOWED_USER_IDS together; docs/slack.md
documents the app manifest and setup.
- Deliver caption-less file uploads to Codex with attachment descriptions
  instead of silently dropping them after download.
- Reject conversation-scoped /telex subcommands in channels with guidance
  (each thread is its own conversation; a slash command carries no thread),
  instead of acting on a conversation key no message flow creates.
- Anchor thread replies to the latest scheduled-run notification published
  in that thread so reply context resolves despite Slack's flat threads.
- Escape Slack entities in approval prompts, selection updates, and
  attachment-failure notices; raw < > & mangled approval text and could
  ping @channel through Codex-controlled content.
- Deduplicate redelivered Socket Mode envelopes by envelope_id so slash
  commands and button clicks cannot execute twice after a reconnect.
- Send only unposted chunks through the slash-command response webhook.
- Refresh active-thread recency when scheduled results are published.
Telegram credentials become optional: each connector is an all-or-nothing
env group and at least one must be configured. Without Telegram, the
Telegram channel, the settings Mini App, and the quick tunnel stay off;
the Slack connector runs standalone.
Multi-stage image running Telex as the unprivileged telex user with all
state under a /data volume. The entrypoint seeds Codex config with
sandbox_mode danger-full-access on fresh volumes: Codex's bubblewrap
sandbox needs user namespaces that Docker's default confinement blocks,
so the container itself is the isolation boundary. Includes a Compose
example and docs/docker.md.
SLACK_ALLOWED_USER_IDS=* authorizes any regular member of the installed
workspace. Membership is verified through users.info against the bot's
team and cached for ten minutes: bots, deactivated accounts, guests, and
Slack Connect participants from other workspaces stay rejected, and
deactivating someone locks them out without a restart. Scheduled-run
owner re-checks go through the same gate.
gh reads GH_TOKEN from the environment; when set, the entrypoint also
wires git's HTTPS credential helper through gh so clones and fetches
work headlessly.
/telex config in the bot DM now renders interactive Codex settings from
Slack blocks (model, reasoning effort, speed tier, approvals, sandbox,
web search) through CodexConfigService with optimistic versioning —
replacing the Telegram-only Mini App pointer.

SLACK_ADMIN_USER_IDS optionally restricts instance-wide commands
(config, login, logout, reload, restart, update) to listed users; the
gate also covers the mention-text command form and config buttons.
Slack rejects chat.update/postMessage payloads far below the documented
40k ceiling (msg_too_long observed at 12k), which both truncated long
answers and, because delivery shared one try block, dropped every
remaining chunk after the first failure. The message limit drops to
3,900 characters and each chunk now posts independently, with a notice
when parts fail.

The final answer no longer silently edits the thinking message — the
progress message freezes without the streaming cursor and the answer
arrives as fresh messages that actually notify. Markdown tables render
as aligned monospace blocks instead of raw pipes.
A mention inside an existing thread calls the bot into a running
discussion. The channel now fetches the earlier thread messages through
conversations.replies (up to 100, oldest dropped over an 8k character
budget) and prefixes them as context for Codex, with display names
resolved and the triggering message excluded. Commands and already
active threads skip the fetch, and a fetch failure degrades to the
bare message.
Follow-ups in a thread the bot already answered no longer trigger it:
with workspace-wide access, humans discussing inside such a thread had
every message routed to Codex. A mention is now required each time; the
engaged-thread set survives only to skip re-reading thread history on
repeat mentions, and thread context still arrives on the first one.
Every inbound message logs the sender (user ID and display name),
conversation, command, and text; per-turn child loggers carry that
identity into the stream, which now mirrors the run: each Codex tool
call once, reasoning summaries as they change, and the delivered
answer. Rollouts never recorded who triggered a turn, so operators had
no way to attribute usage.
Codex referenced workspace files as markdown links to container paths,
which render as dead links in Slack and Telegram. The remote-client
context now instructs Codex to cite code as repo-relative inline paths
or full repository URLs, and the Slack converter renders any non-URL
link target as inline code instead of a broken <path|label> link.
- Comment out the Telegram samples in .env.example: uncommented
  placeholders fail validation in a Slack-only copy.
- Let the entrypoint start as root only to chown freshly created
  volumes (non-recursively), then drop to the telex user via runuser;
  fresh named volumes are root-owned and previously broke first start.
- Install gh for the image architecture instead of hard-coded amd64.
- Cache display names only on successful lookups so a transient
  users.info failure does not pin the raw ID until restart.
- Derive slash-command isDirect from the channel ID prefix; a channel
  literally named directmessage could spoof channel_name.
- Require https in the Slack file-host check, cap downloads at 100 MB
  up front, and count streamed bytes so a wrong size cannot bypass it.
- Clamp the streaming preview and the frozen progress text so entity
  escaping cannot push a chat.update past the message limit.
- Drop unencodable command buttons with a warning instead of failing
  the whole scheduled delivery; bound both response webhooks with a
  10s abort timeout; resolve thread-context names concurrently.
- Extend the fenced-code and final-delivery tests per review.
@sadfun
sadfun marked this pull request as ready for review August 6, 2026 21:10
@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds a complete Slack Socket Mode connector alongside Telegram, including authorization, threaded conversations, commands, approvals, file transfer, settings, and scheduled notifications. It also generalizes shared channel and bridge behavior for multi-provider operation.

  • Adds Slack event routing, authorization, formatting, file handling, interactive controls, and streamed replies.
  • Supports Slack-only and dual-provider configuration and startup.
  • Extends scheduled-run delivery and reply-context recovery to Slack.
  • Extracts shared progress and provider contracts used by Telegram and Slack.

Confidence Score: 4/5

The scheduled-result restart fallback should be fixed before merging because it can inject unrelated automation output into ordinary Slack thread conversations.

After restart, Slack supplies only a thread-root reply reference, and the new fallback interprets any reply in a matching conversation as a reply to its newest delivered scheduled notification.

Files Needing Attention: src/automations/engine.ts and src/channels/slack/channel.ts

Important Files Changed

Filename Overview
src/channels/slack/channel.ts Implements the Slack connector lifecycle, authorization, routing, interactions, thread handling, and provider API adapter.
src/channels/slack/reply.ts Implements bounded, entity-safe Slack replies, streaming progress, action blocks, choices, and attachment uploads.
src/channels/slack/file.ts Adds bounded authenticated file downloads with Slack-host validation and partial-file cleanup.
src/automations/engine.ts Adds restart recovery for Slack notification context, but the fallback incorrectly applies the latest scheduled result to unrelated replies in the same conversation.
src/config/env.ts Adds connector-dependent Slack and Telegram configuration validation.
src/core/bridge.ts Generalizes bridge behavior and lifecycle plumbing for multiple messaging providers.
src/index.ts Initializes configured Telegram and Slack connectors and supports Slack-only operation.

Sequence Diagram

sequenceDiagram
  participant U as Slack user
  participant S as Slack Socket Mode
  participant C as SlackChannel
  participant B as CodexBridge
  participant A as ScheduledRunsEngine
  participant X as Codex
  U->>S: Message, command, or button action
  S->>C: Socket envelope
  C-->>S: Acknowledge
  C->>C: Authorize and route conversation
  C->>A: Resolve scheduled-result reply context
  C->>B: InboundMessage
  B->>X: Start or continue Codex turn
  X-->>B: Progress and final response
  B-->>C: Stream and attachments
  C-->>U: Threaded Slack messages
Loading

Reviews (1): Last reviewed commit: "Remove GitHub auth bootstrap" | Re-trigger Greptile

Comment thread src/automations/engine.ts Outdated
@sadfun
sadfun merged commit 6870b15 into main Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants