WS Slack-UX Feature 2. When the inbound listener acts on an answer in a task thread, it adds a 👍 reaction to that reply so the human sees the machine received it. - SlackListener gains an optional reactor seam; handle_event reacts to the inbound reply message (channel + event ts) AFTER the AUTHZ-01 owner check passes — a non-owner message is rejected and never reacted to. Best-effort: any reaction failure (notably a missing scope) is swallowed and never breaks handle_event or the listen loop. - /new-task is NOT reacted to (a slash command has no reactable message); its "📥 Task received" root post is the acknowledgement. - build_slack_reactor wraps WebClient.reactions_add(name="thumbsup"); the default listener factory wires it best-effort from SLACK_BOT_TOKEN. - Adds reactions:write to the bot scopes in agent-team-manifest.json. NOTE: the new reactions:write scope requires Adam to re-apply the manifest to app A0BCC7TTU66 and reinstall the app. Until then reactions.add returns missing_scope, which the listener swallows (the reaction silently no-ops) — answer handling is unaffected. AUTHZ-01 and the first-answer-wins CAS remain unchanged. |
||
|---|---|---|
| .. | ||
| agent-team-manifest.json | ||
| README.md | ||
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 | A0BCC7TTU66 |
| Bot | agent-team (handle @agentteam2) · user id U0BCFSJ7SUC |
| Scope | Workspace-level app, installed to Sea Haven Industries (T0A46CP6QR3) |
| Manifest | agent-team-manifest.json (source of truth) |
| Settings | https://api.slack.com/apps/A0BCC7TTU66 |
⚠️ Must be a WORKSPACE-LEVEL app (hard lesson, 2026-06-22)
Socket Mode event delivery only works for workspace-level apps. An org-owned app (one created via the Enterprise org/config token /
apps.manifest.create, even when workspace-granted with--org-workspace-grant) connects the socket but receives ZERO workspace Events API events — outboundchat.postMessageworks, but inboundmessage/app_mentionare never delivered, so the clarifier never hears answers. The first build hit exactly this with the now-deleted org appA0BC7AT8NUD. Create this app from the dashboard (api.slack.com/apps → Create New App → From manifest) and pick the workspace "Sea Haven Industries" as the dev workspace, NOT the Enterprise org. Then a normal Install to Workspace works (no org-grant dance). Do not recreate it via the org config token.
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. Inbound message/app_mention arrive as the
Events API envelope {"type":"event_callback","event":{...}} and a free-text
thread reply is matched to its question by thread_ts == channel_ref (see
find_open_question_by_channel_ref).
| Capability | Scope / setting | Why |
|---|---|---|
| Post clarifier questions | chat:write |
slack_live.py chat.postMessage |
| Hear thread replies | channels:history / groups:history + message.channels/message.groups |
@app.event("message") |
| Hear DM replies | im:history + message.im |
DM answer path |
| Hear @mentions | app_mentions:read + app_mention |
@app.event("app_mention") |
| Block Kit answers | interactivity.is_enabled |
@app.action(...) |
| Inbound WebSocket | socket_mode_enabled + 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.
Setup (operator, in browser — secrets never echoed)
- Create the app — api.slack.com/apps → Create New App → From an app
manifest → pick workspace "Sea Haven Industries" → paste
agent-team-manifest.json. - Install to Workspace → copy the Bot User OAuth Token (
xoxb-) →SLACK_BOT_TOKEN. - Basic Information → App-Level Tokens → Generate with scope
connections:write→SLACK_APP_TOKEN. - Channel —
/invite @agentteam2into the clarifier channel; itsC0…id →SLACK_CHANNEL_ID. - Owner allowlist —
AGENT_TEAM_SLACK_OWNER_IDS= Adam's Slack user id (U0A3SC48T47), comma-separated if more than one. Fails closed if empty.
All five land in ~/secrev.env on the box (mode 600), never shell history.
Updating the app from the manifest
Edit agent-team-manifest.json, then in the dashboard (App Manifest tab) paste
the updated manifest, or use apps.manifest.update with an app config token
scoped to the workspace app (the org config token can read/manage it as org
owner, but keep the app workspace-level — do not re-create it org-owned).