Slack adapter
Slack is an optional Socket Mode adapter and MCP client of Guardian.
1. Create the Slack app
Create an app in the Slack API console and:
- enable Socket Mode;
- create an app-level token with
connections:write; - grant the bot
app_mentions:read,chat:write, and the history scopes needed for the channel types you will allow; - subscribe to
app_mentionplus the message events needed for those channel types; and - install the app to the workspace.
Store the bot and app tokens through the CLI:
fhold portal token slack \
--bot-token-file /private/path/to/bot-token \
--app-token-file /private/path/to/app-token
Both files must be mode 0600. Do not store the values in Compose environment variables.
In fhold Admin, Apps → Slack presents the same scopes and event checklist and opens Slack's app console. Bot tokens → Save Slack tokens stores them privately. Both tokens are required initially; afterward either one can be rotated without re-entering the other. Default access, allowed-user rules and individual user mappings are in the same Slack section. Save Slack settings does not save another app's drafts. Restart now or later when prompted; enabling Slack also enables the MCP service it needs.
2. Configure a default-deny scope
Configure access through validated stack intent:
fhold portal access slack --channels C0123456789 --no-apply
Values are comma-separated Slack IDs. Every non-empty allowlist must match. A blocked user always loses access. Configure users alone to allow direct messages; a DM cannot satisfy a channel constraint. The adapter refuses all use when both allowlists are empty.
In the revised Admin preview, open Apps → Slack → Who can use the bot and enter the same IDs. Choose Chat only, Read files or Full access under What can Slack do?, then select Save Slack settings. Normal bot setup does not ask you to choose or copy a fhold key; the existing credential remains private plumbing. Full access requires confirmation. If a required scope or token is missing, Admin opens and focuses the field that needs attention. The preview has not yet been live-verified; see the Admin runbook.
Different permissions for a person lets you enter an exact Slack user ID and choose their permissions with Save person permissions, without naming a key. The user must still pass the allowlist. Existing mappings retain their credential IDs. Editing saved permissions affects every use of that identity and requires confirmation; ordinary edits preserve the existing conversations and bot assignment. Use bot permissions removes an override, not access checks. Existing permission editing is under Apps → Advanced access → Manage. Key rotation, when needed, is under System → Connection keys; it is not part of bot setup.
3. Enable and verify
fhold credential set-policy slack chat
fhold portal credential slack --credential slack --no-apply
fhold portal enable slack
fhold status
fhold logs
chat is the safe default for a shared chat platform. read additionally lets
the agent inspect non-secret content in /stash and /work; full inherits Assistant tool
permissions and should be used only when both the Slack allowlist and every
permitted user are trusted to trigger state-changing work.
Default chat does not grant knowledge reads or task management. If a trusted
personal operator requires those capabilities, assign a separate full
credential explicitly to that exact allowed Slack user; mapping does not
replace the channel/user allowlist.
The selected credential is the fallback for every allowed Slack user. Map an exact Slack user ID to another named credential when that user needs a different policy:
fhold credential add support-read read
fhold credential map slack U012ABCDEF support-read
fhold credential mappings slack
Remove the override with fhold credential unmap slack U012ABCDEF. Channel,
user, and block-list checks still apply; a credential mapping never grants
portal access. The portal receives only a generated keyring for its fallback
and mapped credentials. Guardian OAuth issuer/subject mappings use the same
registry for remote MCP clients; Slack itself continues to use exact
platform-user mappings.
Mention the app in an allowed channel or message it directly when the user
scope permits that. Thread replies retain an opaque, credential-scoped Guardian
conversation handle. Changing a user's mapping starts fresh policy continuity.
Send /clear or !clear to reset it.
The Slack adapter is intentionally a conversational subset of the MCP catalog.
If a full agent pauses for a permission decision, the adapter tells the user
to complete that explicit decision with a full MCP client; chat text is never
treated as permission approval.
Continuity state is stored at data/portal/slack/portal.db.
Existing bot/app token files can be configured through fhold portal token
with --no-apply. Keep those files private and configure fhold's own allowlist
and credential mappings before enabling Slack.
Verify Socket Mode login, an allowed message, a denied user/channel, and the
configured policy independently; healthy containers alone do not prove them.