This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
orchestrator/agent-team/slack
Adam Moussa f59b293022
fix(agent-team): repair Slack listener block_actions matcher; add dedicated Slack app (#25)
The Socket Mode inbound listener crashed at registration time on first live
run: `@app.action({})` raised `BoltError: action ({}) must be any of str,
Pattern, and dict` under slack_bolt 1.28.0, killing the listener thread (the
whole inbound answer path — message/app_mention/block_actions — went down,
caught only by the coordinator's respawn watchdog). serve() is marked
`# pragma: no cover - live socket`, so this was never exercised until the R720
bring-up. Replace the unsupported empty-dict matcher with a catch-all
`re.compile(r".*")` action_id regex; handle_event still does the real filtering
+ AUTHZ-01 owner-allowlist gate, so over-matching is safe.

Verified on sh-secrev: listener connects (live Socket Mode WebSocket), outbound
chat.postMessage works, 0 errors. /sh-security-review PASS (no confirmed
critical/high; matcher change introduces no new findings).

Also adds the dedicated Slack app (manifest + README) backing the clarifier
gate — "Sea Haven agent-team" (A0BC7AT8NUD), workspace-scoped install to avoid
the Enterprise-Grid `scope_not_allowed_on_enterprise` org-install trap — and
patches the provisioning runbook's stale langgraph pin (1.1.10 -> 1.2.5).
2026-06-22 13:16:35 -04:00
..
agent-team-manifest.json fix(agent-team): repair Slack listener block_actions matcher; add dedicated Slack app (#25) 2026-06-22 13:16:35 -04:00
README.md fix(agent-team): repair Slack listener block_actions matcher; add dedicated Slack app (#25) 2026-06-22 13:16:35 -04:00

agent-team Slack app

Dedicated Slack app backing the Plane-2 clarifier human-gate (Socket Mode). Kept separate from the webhook-only Tech Notifications app (A0ARYQZU3KJ) that the nightly secrev sweep uses, to isolate the two-way bot's trust surface.

Field Value
App name Sea Haven agent-team
App ID A0BC7AT8NUD
Org / team seahaven (E0A524V806L)
Manifest agent-team-manifest.json (source of truth)
Settings https://api.slack.com/apps/A0BC7AT8NUD

Why these scopes (verified against the code)

agent_team/transport/slack_listener.py subscribes over Socket Mode to message, app_mention, and Block Kit block_actions; slack_live.py posts questions via chat.postMessage.

Capability Scope / setting Why
Post clarifier questions chat:write slack_live.py chat.postMessage
Hear thread replies in the channel channels:history / groups:history + message.channels/message.groups events @app.event("message")
Hear DM replies im:history + message.im event DM answer path
Hear @mentions app_mentions:read + app_mention event @app.event("app_mention")
Block Kit button/select answers interactivity.is_enabled @app.action({})
Inbound WebSocket socket_mode_enabled + an app-level token w/ connections:write VPN-only box, no public HTTPS endpoint

Inbound auth is NOT scope-based: AUTHZ-01 (AGENT_TEAM_SLACK_OWNER_IDS) gates the sender and fails closed. Socket membership alone is never authorization.

Remaining manual token mints (operator, in browser)

Both produce secrets — paste them straight into ~/secrev.env on the box (mode 600), never into shell history.

  1. Bot token (xoxb-) — https://api.slack.com/apps/A0BC7AT8NUD/oauth → Install to Workspace → approve → copy the Bot User OAuth Token → SLACK_BOT_TOKEN.
  2. App-level token (xapp-) — https://api.slack.com/apps/A0BC7AT8NUD/general → App-Level Tokens → Generate Token and Scopes → add scope connections:write → copy → SLACK_APP_TOKEN.
  3. Channel — create/choose the clarifier channel, /invite @agent-team, copy its C0... id → SLACK_CHANNEL_ID.
  4. Owner allowlist — AGENT_TEAM_SLACK_OWNER_IDS = Adam's Slack user id (U0A3SC48T47), comma-separated if more than one. Gate fails closed if empty.

Reproduce / update the app from the manifest

TOKEN=$(python3 -c "import json;print(json.load(open(os.path.expanduser('~/.slack/credentials.json')))['E0A524V806L']['token'])")
# validate
curl -s -X POST https://slack.com/api/apps.manifest.validate \
  -H "Authorization: Bearer $TOKEN" --data-urlencode "manifest=$(cat agent-team-manifest.json)"
# update existing app
curl -s -X POST https://slack.com/api/apps.manifest.update \
  -H "Authorization: Bearer $TOKEN" \
  --data-urlencode "app_id=A0BC7AT8NUD" \
  --data-urlencode "manifest=$(cat agent-team-manifest.json)"