Skip to content

feat(slack): reproducible "all channels" wiring (list + invite helpers) - #19

Merged
dizhaky merged 2 commits into
mainfrom
claude/hermes-slack-bidirectional-pu404e
Jun 16, 2026
Merged

feat(slack): reproducible "all channels" wiring (list + invite helpers)#19
dizhaky merged 2 commits into
mainfrom
claude/hermes-slack-bidirectional-pu404e

Conversation

@dizhaky

@dizhaky dizhaky commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

Task: wire the Hermes agent to all Slack channels, bidirectionally.

After auditing the repo, most of this already exists — so this PR fills the one genuine gap rather than reinventing wiring.

What already exists (verified, no changes needed)

  • Bidirectional Socket Modegateway/platforms/slack.py already uses slack-bolt AsyncSocketModeHandler with SLACK_BOT_TOKEN (xoxb-) + SLACK_APP_TOKEN (xapp-), listens for app_mention / message.*, replies in-thread, handles slash commands, reactions, file uploads, and multi-workspace.
  • Outbound to channelschat:write + SlackAdapter.send().
  • Persistent run on macOShermes gateway service install generates an ai.hermes.gateway launchd LaunchAgent with KeepAlive, so the Socket Mode client reconnects on wake/reboot.
  • Manifest generationhermes slack manifest.

The gap this PR closes — "all channels"

A Slack bot only sees/posts in channels it has joined, and there's no bulk-add API. That made "all channels" a manual checklist. New helpers make it reproducible:

  • hermes slack channels — list every channel the bot token can see and report which it is / isn't a member of (audits coverage, reports gaps).
  • hermes slack invite [--all | --channel NAME/ID] [--user-token] [--dry-run] — self-join public channels via conversations.join; invite the bot to private channels via conversations.invite when a user token is supplied.

Also:

  • Added channels:join bot scope to the generated manifest so self-join works.
  • Added hermes slack manifest --yaml (Slack accepts JSON or YAML).
  • Documented SLACK_USER_TOKEN, the connections:write app-token requirement, and the invite-per-channel (safe default) vs read-all user token trade-off.

Tests

tests/hermes_cli/test_slack_cli.py — channel listing/pagination, public-join vs private-skip vs user-token-invite paths, already_in_channel handling, and JSON/YAML manifest rendering. All 13 pass; full Slack suite (199) green; ruff clean.

Operator action items (only you can do these)

  1. At api.slack.com: create/configure the app from the manifest (hermes slack manifest --yaml), enable Socket Mode, generate the xapp- app token with connections:write, install to workspace.
  2. Put SLACK_BOT_TOKEN + SLACK_APP_TOKEN in ~/.hermes/.env.
  3. Run hermes slack invite --all, then verify: @mention the bot (in-thread reply), post outbound, and confirm the launchd job logs "Socket Mode connected".
  4. Decide invite-per-channel (bot token, default) vs read-all (user token) — see the docs note.

Note: kb-daemon (sibling repo) uses SLACK_BOT_TOKEN etc. for outbound only — env-var names are kept consistent and non-colliding.

https://claude.ai/code/session_01XMJSckDomPtewEipAjfSGD


Generated by Claude Code

The Slack Socket Mode adapter (bidirectional) and launchd LaunchAgent
already exist. The missing piece was reproducible "all channels" wiring:
a Slack bot only sees/posts in channels it has joined, and there's no
bulk-add API.

Add two CLI helpers:
- `hermes slack channels` — list channels and report which ones the bot
  is / isn't a member of (audits coverage, reports gaps).
- `hermes slack invite [--all|--channel] [--user-token] [--dry-run]` —
  self-join public channels via conversations.join; invite the bot to
  private channels via conversations.invite when a user token is given.

Also:
- add `channels:join` bot scope to the generated manifest so self-join works
- add `hermes slack manifest --yaml` (Slack accepts JSON or YAML)
- document SLACK_USER_TOKEN, the connections:write app-token requirement,
  and the invite-per-channel vs read-all (user token) trade-off
- tests for channel listing, invite paths, and manifest rendering
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

🔎 Lint report: claude/hermes-slack-bidirectional-pu404e vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9024 on HEAD, 9021 on base (🆕 +3)

🆕 New issues (2):

Rule Count
unresolved-import 2
First entries
tests/hermes_cli/test_slack_cli.py:5: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
hermes_cli/slack_cli.py:241: [unresolved-import] unresolved-import: Cannot resolve imported module `slack_sdk`

✅ Fixed issues: none

Unchanged: 4795 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

The fetchNpmDeps hash in nix/web.nix drifted from web/package-lock.json
(pre-existing on main after an earlier npm dependabot bump), failing the
`nix` build check. Update to the hash computed by the nix build itself.
@dizhaky
dizhaky marked this pull request as ready for review June 16, 2026 19:27
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dizhaky
dizhaky merged commit 6a0c3b7 into main Jun 16, 2026
25 of 28 checks passed
@dizhaky
dizhaky deleted the claude/hermes-slack-bidirectional-pu404e branch June 17, 2026 15:08
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