Install
$ agentstack add mcp-jeremylongshore-claude-code-slack-channel Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
claude-code-slack-channel v0.12.0
The Slack-native governance substrate for Claude Code — the kernel other governance tooling builds on. Humans, Claude Code sessions, and peer agents converse safely in shared channels: every tool call passes through a declarative, tier-aware policy engine; every decision lands in a hash-chained, Ed25519-signed audit journal you can verify offline. Per-thread session isolation, identity-aware permission gates, operator admin commands with cross-channel approval, multi-agent loop control + backpressure, lease-fenced sessions that survive a process crash with loss-proof reply delivery, and defense-in-depth against prompt injection. The policy/journal/relay kernel here is the substrate that the companion [agent-governance-plane (AGP)](#companion-tooling) reimplements for cross-runtime governance.
[](https://github.com/jeremylongshore/claude-code-slack-channel/actions/workflows/ci.yml) [](LICENSE) [](https://scorecard.dev/viewer/?uri=github.com/jeremylongshore/claude-code-slack-channel)
Links: [Roadmap & Scope](ROADMAP.md) · Gist One-Pager · GitHub Pages · Release Notes
> Research Preview — Channels require Claude Code v2.1.80+ and claude.ai login.
How It Works
Slack workspace (cloud)
↕ WebSocket (Socket Mode — outbound only, no public URL)
server.ts (local MCP server, spawned by Claude Code)
↕ stdio (MCP transport)
Claude Code session
Socket Mode means no public URL needed — works behind firewalls, NAT, anywhere.
Quick Start
For AI-assisted setup: run /slack-channel:install and your AI assistant will walk you through every step below. The install skill also supports doctor (health check), verify (round-trip test), repair (auto-fix), manifest (one-click Slack-app import), reset, tour, and uninstall modes — see [skills/install/SKILL.md](skills/install/SKILL.md).
Prerequisites
Before step 1, confirm you have:
- Bun ≥ 1.0 — install with
curl -fsSL https://bun.sh/install | bash. Node.js / Docker fallbacks are documented in [Option B](#option-b-nodejs--npx) / [Option C](#option-c-docker) below. - Claude Code ≥ v2.1.80 — see https://docs.claude.com/claude-code/install for upgrade.
claude.ailogin — this is a Research Preview constraint. API-key-only auth (ANTHROPIC_API_KEYset with noclaude.aisession) does NOT work for Channels. Runclaude loginto complete the browser flow.
1. Create a Slack App
- Go to api.slack.com/apps → Create New App → From scratch
- Socket Mode: Settings → Socket Mode → Enable → Generate App-Level Token (
xapp-...) withconnections:writescope - Event Subscriptions: Enable → Subscribe to bot events:
message.im— DMsmessage.channels— public channelsmessage.groups— private channelsapp_mention— @ mentions
- Bot Token Scopes (OAuth & Permissions):
chat:write— send messageschannels:history— read public channelsgroups:history— read private channelsim:history— read DMsreactions:write— add reactionsfiles:read— download shared filesfiles:write— upload filesusers:read— resolve display names
- Install to Workspace → Copy Bot Token (
xoxb-...)
2. Configure Tokens
/slack-channel:configure xoxb-your-bot-token xapp-your-app-token
3. Run
Pick your runtime:
Option A: Bun (recommended)
bun install
# Current (claude-code-plugins marketplace):
claude --channels plugin:slack-channel@claude-code-plugins
# Future (after upstream approval):
# claude --channels plugin:slack-channel@claude-plugins-official
Option B: Node.js / npx
npm install
# In .mcp.json, change command to: "npx", args: ["tsx", "server.ts"]
claude --channels plugin:slack-channel@claude-code-plugins
Option C: Docker
docker build -t claude-slack-channel .
# In .mcp.json, change command to: "docker", args: ["run", "--rm", "-i", "-v", "~/.claude/channels/slack:/state", "claude-slack-channel"]
claude --channels plugin:slack-channel@claude-code-plugins
3.5. Add the bot to your Slack channel
This step is the most common silent failure. Slack installs apps to the workspace without joining any channels. The pairing DM in step 4 works because DMs auto-route, but a channel test message in step 5 will hit silence — the bot literally isn't in the channel to see the event.
- Open Slack → navigate to the channel where you want the bot to live
- Click the channel name at the top → Integrations tab
- Click Add an App → select your bot
- Confirm: the bot now appears in the channel's member list
Private channels need explicit invitation. Repeat per channel if the bot needs to be in more than one.
4. Pair Your Account
- DM the bot in Slack — you'll get a 6-character pairing code
- In your terminal:
/slack-channel:access pair - You're connected. Chat away.
5. Verify it's working
In the channel where you added the bot in step 3.5, send:
@ hello
The bot should reply within 10 seconds. If you get silence, run /slack-channel:install doctor for a structured diagnosis, then /slack-channel:install repair to auto-fix what's fixable. See [Troubleshooting](#troubleshooting) for the top failure modes.
Troubleshooting
The five silent-failure modes that cover ~95% of fresh-install issues:
- Bot is not in the channel — see step 3.5 above. Channel test messages hit silence because the bot can't see the event.
- Claude Code version too old — run
claude --version; need ≥ v2.1.80. claude.ailogin missing —ANTHROPIC_API_KEYalone is not accepted (Research Preview constraint). Runclaude login.- Bun not installed —
bun: command not found. Install withcurl -fsSL https://bun.sh/install | bashor use the Node.js fallback in Option B. - Wrong file permissions on
.env— must be0600. Runchmod 0600 ~/.claude/channels/slack/.env, or run/slack-channel:install repair.
Full troubleshooting matrix (10 failure modes): [skills/install/references/troubleshooting.md](skills/install/references/troubleshooting.md).
Policy Engine (v0.6.0+)
Author rules in access.json.policy to automate permission decisions for Claude Code tool calls. Three rule effects, evaluated strictest-tier-first then first-applicable within a tier (detailed below):
{
"policy": [
{
"id": "safe-reads-in-ops",
"effect": "auto_approve",
"match": { "tool": "Read", "channel": "C_OPS_DOCS" }
},
{
"id": "no-shell",
"effect": "deny",
"match": { "tool": "Bash" },
"reason": "Shell execution is not permitted."
},
{
"id": "dangerous-writes",
"effect": "require_approval",
"match": { "tool": "Write", "channel": "C_DEPLOY" },
"approvers": 2,
"ttlMs": 300000
}
]
}
auto_approve— skip the Block Kit prompt; the tool call runs immediately and apolicy.allowevent is journaled.deny— the reason is posted back into the originating thread and the call is rejected.policy.denyis journaled.require_approval— route through human approver(s).approvers: 2requires two distinct Slackuser_ids (NIST two-person integrity; the same user cannot double-satisfy quorum by clicking twice). A single deny from any allowlisted user rejects the request immediately regardless of quorum count.- Successful approvals grant a TTL window scoped to
(rule, channel, thread)so a chain of similar calls doesn't re-prompt. - Parse errors in
access.json.policyare fatal at boot — policy is safety-critical, silent degradation is not offered. Missing or emptypolicyis fine (first-install path).
Tier-aware evaluation: rules carry a tier (admin → user → workspace → default). Evaluation is strictest-tier-wins — a higher tier's deny cannot be overridden by a lower tier's auto_approve, so a workspace-level guardrail can't be relaxed by a per-user rule. Within a tier, first-applicable ordering holds.
When a call is denied, the result returned to Claude is context-stripped to a bare { behavior: 'deny' } — the rule id and reason are journaled and posted to the thread, but not handed back to the model, so a denied tool call can't be reverse-engineered into a rephrase-and-retry loop.
Full schema reference: [ACCESS.md](ACCESS.md#policy-schema-v050). Decision procedure: [000-docs/policy-evaluation-flow.md](000-docs/policy-evaluation-flow.md). Release scope and what was deliberately deferred: [000-docs/v0.6.0-release-plan.md](000-docs/v0.6.0-release-plan.md).
Access Control
See [ACCESS.md](ACCESS.md) for the full schema.
/slack-channel:access policy allowlist # Only pre-approved users
/slack-channel:access add U12345678 # Add a user
/slack-channel:access remove U12345678 # Remove a user
/slack-channel:access channel C12345678 # Opt in a channel (default: mention-to-engage)
/slack-channel:access channel C12345678 --ambient # Ambient: Claude hears every message
/slack-channel:access status # Show current config
Interaction modes. A newly opted-in channel defaults to mention-to-engage (requireMention: true): people converse freely and Claude only sees messages that @-mention it — and once a human mentions the bot in a thread, they can keep talking in that thread without re-mentioning (peer agents must @-mention every time). Pass --ambient for a dedicated bot channel where Claude hears everything, or --allow to restrict which humans are heard. See [ACCESS.md](ACCESS.md#interaction-modes).
Multi-agent coordination
Channels can opt in to cross-bot message delivery by listing trusted bot user IDs in allowBotIds. Useful when multiple Claude Code instances (or other bots you operate) need to coordinate in a shared channel — e.g., an ops-monitor agent and an engineering agent in #incidents. Default is no cross-bot delivery: every bot message is dropped at the gate. See [ACCESS.md](ACCESS.md) for the full schema and security tradeoffs.
Example access.json entry:
{
"channels": {
"C_INCIDENTS": {
"requireMention": false,
"allowFrom": ["U_OPS_BOT", "U_ENG_BOT", "U_HUMAN"],
"allowBotIds": ["U_OPS_BOT", "U_ENG_BOT"]
}
}
}
Self-echoes from this bot are always filtered regardless of allowBotIds. Peer bots cannot approve permission prompts — the permission relay gates on the top-level allowFrom, not the channel policy.
For the full multi-agent recipe — registering a second bot, configuring allowBotIds mutually, mention-driven addressing, the per-bot rate limit + channel-wide circuit breaker + global session backpressure, per-user session isolation, the !mute/!unmute write verbs and !agents/!mute-status/!rate-limit read-only verbs, common failure modes, what you DON'T get — see [000-docs/multi-agent-channels.md](000-docs/multi-agent-channels.md).
This is a prompt-injection vector by design. The security model is documented threat-model-first in [SECURITY.md](SECURITY.md): (1) the adversary and the four principals, (2) the mitigations below — each with its own stated limit, and (3) an explicit list of what this does NOT protect against (same-UID host compromise, in-process token exposure, supply-chain, Slack/Anthropic platform bugs). Start there for the full picture; the defense-in-depth layers are:
- Sender gating: Every inbound message hits a gate. Ungated messages are silently dropped before reaching Claude.
- Outbound gate: Replies only work to channels that passed the inbound gate.
- File exfiltration guard: Cannot send
.env,access.json,audit.log, or other state files through the reply tool. - Prompt-injection defense: System instructions explicitly tell Claude to refuse pairing/access requests from Slack messages — peer-bot messages carry the same risk as human messages.
- Bot filtering:
bot_idmessages are dropped by default. Channels that host multiple cooperating agents can opt in to specific peers viaallowBotIds; self-echoes are always filtered viabot_id/bot_profile.app_id/usertriple-check. - Link unfurling disabled: All outbound messages set
unfurl_links: false, unfurl_media: false. - Token security:
.envischmod 0o600, never logged, never in tool results. - Static mode: Set
SLACK_ACCESS_MODE=staticto freeze access at boot (no runtime mutation). - Signed audit journal: Every tool-call decision is written to a hash-chained, Ed25519-signed journal (RFC 8785 JCS canonical form). The chain is verifiable offline against a published public key — see [Audit Signing](#audit-signing).
- Admin-command hardening: Operator verbs (
!clear,!restart) route through gate → policy → journal → execute and require a server-minted HMAC nonce confirmed from a second channel. Claude cannot self-invoke them — no MCP tool name begins withadmin.. This closes the EchoLeak / operator-coercion class (CVE-2025-32711, threat T11): a prompt injected into one channel cannot drive a privileged action, because confirmation must come from a channel the attacker doesn't control. - Multi-agent loop control + backpressure: A per-
(channel, bot_id)sliding-window rate limit (default 10 msg/60s) breaks A→B→A runaway loops; a channel-wide circuit breaker trips a 3+-bot ring (A→B→C→A) the pairwise limiter misses; an optional globalmaxConcurrentSessionscap sheds load before file handles / memory are exhausted (journalingsession.activate_rejected). Operators can!mute/!unmutea peer and inspect state read-only with!agents,!mute-status,!rate-limit. Optional per-user session isolation (perUserSessions) gives each sender their own bridge session within a shared thread. - Crash-safe sessions + loss-proof replies: Each active session holds a fencing lease (monotonic token + heartbeat) so exactly one process owns a turn; a boot-time recovery sweep requeues work whose lease lapsed and quarantines anything it cannot prove safe. Replies are recorded as durable obligations before the send and drained by a leased, retrying, dead-lettering poller with idempotency keys — so a transient Slack error or a process crash redelivers exactly once instead of silently dropping the reply. Live for single-message, chunked, and streaming replies (file-upload durability is in progress — see [Reliability & crash-safety](#reliability--crash-safety)).
Each layer's limit, and an explicit "what this does NOT protect against" section, are in [SECURITY.md](SECURITY.md). Trust boundaries, per-primitive attack surface, and threats T1–T11 are documented in [000-docs/THREAT-MODEL.md](000-docs/THREAT-MODEL.md).
Audit Signing
Every decision the gate makes is journaled to ~/.claude/channels/slack/audit.log — hash-chained and, as of v0.10, Ed25519-signed — so a third party can verify the log against a public key without trusting the host.
# Verify a journal end-to-end (hash chain + signatures):
bun server.ts --verify-audit-log ~/.claude/channels/slack/audit.log
# Operator key lifecycle (Ed25519 over RFC 8785 JCS):
bun audit-key-cli.ts init # generate keypair, encrypt private half to .env, print public key
bun audit-key-cli.ts rotate # fresh keypair, re-sign chain head, archive the old public key
bun audit-key-cli.ts verify # verify the log against active + archived public keys
bun audit-key-cli.ts show # print act
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [jeremylongshore](https://github.com/jeremylongshore)
- **Source:** [jeremylongshore/claude-code-slack-channel](https://github.com/jeremylongshore/claude-code-slack-channel)
- **License:** Apache-2.0
- **Homepage:** https://jeremylongshore.github.io/claude-code-slack-channel/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.