Bridge Claude Code sessions to Slack channels
Project description
summon-claude
Bridge Claude Code sessions to Slack channels. Run summon start in a terminal, authenticate from Slack, and interact with Claude entirely through a dedicated Slack channel.
Installation
The package is summon-claude on PyPI; once installed, the CLI command is summon.
Option A: uv tool (Recommended)
uv tool install summon-claude
Option B: pipx
pipx install summon-claude
Option C: Homebrew (macOS/Linux)
brew install wgordon17/summon/summon-claude
Keeping up to date
summon checks for new versions on summon start and notifies you when an update is available.
To upgrade to the latest version:
| Installation method | Upgrade command |
|---|---|
| uv tool | uv tool upgrade summon-claude |
| pipx | pipx upgrade summon-claude |
| Homebrew | brew upgrade summon-claude |
To disable update checks, set the environment variable:
export SUMMON_NO_UPDATE_CHECK=1
Quick Start
# 1. Set up your Slack app (see Slack App Setup below)
# 2. Run the interactive setup wizard
summon init
# 3. Start a session
summon start
Slack App Setup
Import the manifest (recommended)
- Go to api.slack.com/apps
- Click Create New App → From an app manifest
- Select your workspace
- Paste the contents of
slack-app-manifest.yaml - Click Create, then Install to Workspace
Collect your tokens
| Token | Where to find it |
|---|---|
Bot Token (xoxb-...) |
OAuth & Permissions → Bot User OAuth Token |
App Token (xapp-...) |
Settings → Basic Information → App-Level Tokens → Generate one with connections:write scope |
| Signing Secret | Settings → Basic Information → App Credentials |
Auth Flow
- Run
summon startin your terminal - The terminal prints:
================================================== SUMMON CODE: ABC123 Type in Slack: /summon ABC123 Expires in 5 minutes ================================================== - In Slack, type
/summon ABC123 - The bot verifies the code, creates a session channel, and posts a header
- All further interaction happens in that Slack channel
The code expires in 5 minutes. Run summon start again to get a new one.
Commands
| Command | Description |
|---|---|
summon --version |
Show CLI version |
summon version |
Show version and environment info (Python, platform, paths) |
summon init |
Interactive setup wizard — creates config file with your tokens |
summon start |
Start a new session (prints auth code, waits for /summon in Slack) |
summon session list |
Show active sessions (use --all for all recent) |
summon session info SESSION_ID |
Show detailed view of one session |
summon session stop SESSION_ID |
Send SIGTERM to a running session |
summon session logs [SESSION_ID] |
View session logs (list files, or tail a specific session) |
summon session cleanup |
Mark sessions with dead processes as errored |
summon config show |
Show current config file (tokens masked) |
summon config set KEY VALUE |
Set a single config value |
summon config path |
Print the config file path |
summon config edit |
Open config file in $EDITOR |
summon config check |
Validate config file (keys, token format, DB writability, Slack API connectivity) |
Alias:
summon sis shorthand forsummon session(e.g.,summon s list).
summon start flags
| Flag | Description |
|---|---|
--cwd PATH |
Working directory for Claude (default: current directory) |
--name NAME |
Session name used for Slack channel naming |
--model MODEL |
Override the default Claude model |
--resume SESSION_ID |
Resume an existing Claude Code session by ID |
-b, --background |
Run session in background as daemon (logs accessible via summon session logs) |
Global flags
| Flag | Description |
|---|---|
-h, --help |
Show help message and exit |
--version |
Show version and exit |
-v, --verbose |
Enable verbose logging |
-q, --quiet |
Suppress non-essential output (mutually exclusive with --verbose) |
--no-color |
Disable colored output (respects NO_COLOR environment variable) |
--config PATH |
Override config file location (default: XDG-aware path) |
-o, --output {json|table} is available on version, session list, and session info (default: table).
In-Session Commands
Once a session is active in Slack, type !-prefixed commands to control the session without reaching Claude:
| Command | Description |
|---|---|
!help |
Show all available commands |
!status |
Show session status (model, turns, cost, uptime) |
!end |
End the current session |
!model |
Show the active model |
!model <name> |
Switch model (takes effect on next session start) |
Aliases: !quit, !exit, and !logout all map to !end.
Passthrough commands: Claude SDK slash commands (e.g., /compact, /clear) are also available as !compact, !clear, etc. — they are forwarded to the SDK as their / equivalents.
Blocked commands: !login is blocked in Slack sessions.
Use !help in a session to see the full list, including any passthrough commands discovered from the SDK.
Configuration
Config is loaded in priority order: environment variables → config file → local .env.
Config file path (XDG-aware)
$XDG_CONFIG_HOME/summon/config.env # if XDG_CONFIG_HOME is set
~/.config/summon/config.env # default on most systems
~/.summon/config.env # fallback if ~/.config doesn't exist
Use summon config path to see which path is active. Use summon init to create the file interactively.
Required variables
| Variable | Description |
|---|---|
SUMMON_SLACK_BOT_TOKEN |
Bot token (xoxb-...) from OAuth & Permissions |
SUMMON_SLACK_APP_TOKEN |
App-level token (xapp-...) for Socket Mode |
SUMMON_SLACK_SIGNING_SECRET |
Signing secret from Basic Information |
Optional variables
| Variable | Default | Description |
|---|---|---|
SUMMON_DEFAULT_MODEL |
(SDK default) | Default Claude model |
SUMMON_CHANNEL_PREFIX |
summon |
Prefix for created session channels |
SUMMON_PERMISSION_DEBOUNCE_MS |
500 |
Debounce window for batching permission requests (ms) |
SUMMON_MAX_INLINE_CHARS |
2500 |
Threshold for inline vs file upload display |
SUMMON_NO_UPDATE_CHECK |
(unset) | Set to 1 to disable update notifications on summon start |
A local .env in the project directory overrides the config file.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Slack │
│ (channels, messages, files, interactive buttons, slash cmd) │
└──────────────────────────┬──────────────────────────────────────┘
│ Socket Mode
▼
┌─────────────────────────────────────────────────────────────────┐
│ SummonSession (Orchestrator) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Claude SDK │ Slack Bolt │ Auth │ Permissions │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ Claude SDK │ │ ChatProvider │
│ (streaming) │ │ (Slack adapter) │
└──────────────────────┘ └──────────────────────┘
Threading Model
Messages are organized into threads to keep the main channel clean:
- Main channel: Opens with the initial prompt and closes with Claude's final conclusion
- Turn threads: Each Claude turn's tool calls post to a dedicated turn thread with a summary like "🔧 Turn 3: 5 tool calls · session.py, config.py"
- Subagent threads: When Claude spawns subagents, their activity posts to dedicated subagent threads
- Permissions: Permission requests broadcast to all threads with
<!channel>notifications
This structure keeps the main conversation readable while preserving full context in threads.
Provider Abstraction
All Slack API calls go through a ChatProvider protocol, enabling future support for Discord, Teams, or CLI providers without changing core routing logic. The SlackChatProvider implements this protocol for Slack.
Modules
| Module | Purpose |
|---|---|
cli.py |
CLI entry point: global flags (--version, --quiet, --no-color, --config), subcommands |
cli_config.py |
Config subcommand handlers: show, path, edit, set, check |
config.py |
pydantic-settings config with XDG path resolution and plugin discovery |
auth.py |
8-char hex short codes with 5-min TTL, brute-force protection (5 attempts) |
registry.py |
SQLite session registry with WAL mode, heartbeat, audit log |
channel_manager.py |
Slack channel create/archive/header with collision handling |
permissions.py |
Debounced permission batching with Slack interactive buttons |
content_display.py |
Hybrid inline/file upload display with diff formatting |
streamer.py |
Claude response streaming to Slack with threaded routing |
thread_router.py |
Routes content to main channel, turn threads, and subagent threads |
commands.py |
!-prefixed command dispatch: local handlers, passthrough, blocking, aliasing |
session.py |
Core orchestrator: ties all modules together |
mcp_tools.py |
In-process MCP server: slack_upload_file, slack_create_thread, slack_react, slack_post_snippet |
providers/base.py |
ChatProvider protocol and message/channel abstractions |
providers/slack.py |
SlackChatProvider implementation for Slack API calls |
rate_limiter.py |
Per-key cooldown rate limiter for slash command spam protection |
update_check.py |
PyPI update checker with 24h cache, shown on summon start |
_formatting.py |
Slack mrkdwn formatting helpers and tool argument extraction |
Security
Authentication
summon startgenerates a short code (8 hex characters)- Short code is printed to the terminal only — it is never sent to Slack automatically
- You type
/summon <code>in Slack; the bot verifies the code against the registry - Code expires after 5 minutes; locked after 5 failed attempts
/summonhas a 2-second per-user rate limit
Permission handling
- Auto-approved tools:
Read,Grep,Glob,WebSearch,WebFetch,LSP, and other read-only operations - User-approved tools:
Write,Edit,Bash, and other destructive operations - Approval requests are debounced (default 500ms) and batched into a single Slack message
- Timeout: 5 minutes — unanswered permission requests are denied automatically
Audit logging
All session events (session_created, auth_attempted, auth_succeeded, auth_failed, session_active, session_ended, session_errored, session_stopped) are written to the SQLite registry for audit purposes.
Development
make install # uv sync + install git hooks
make lint # ruff check + format (auto-fix)
make test # pytest with asyncio
make build # build sdist and wheel
make clean # remove build artifacts and cache
make all # install → lint → test
make py-typecheck # pyright type checking
make py-test-quick # fast tests (exclude slow, fail-fast)
make repo-hooks-install # install prek pre-commit hooks
make repo-hooks-clean # remove hooks and cache
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file summon_claude-0.1.0.tar.gz.
File metadata
- Download URL: summon_claude-0.1.0.tar.gz
- Upload date:
- Size: 187.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79f6e31b809e1b1ee559dc1bc42c0c8033478ee861fbb02c03ec1da554e29950
|
|
| MD5 |
1f4d2a6d7c551d6a5d8ea8ba29ed538a
|
|
| BLAKE2b-256 |
0a66483e2d31ac0e264c73964c0ab5893af616c72c46b5b5b58e7dc8b44b39d6
|
Provenance
The following attestation bundles were made for summon_claude-0.1.0.tar.gz:
Publisher:
publish.yaml on wgordon17/summon-claude
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
summon_claude-0.1.0.tar.gz -
Subject digest:
79f6e31b809e1b1ee559dc1bc42c0c8033478ee861fbb02c03ec1da554e29950 - Sigstore transparency entry: 992577115
- Sigstore integration time:
-
Permalink:
wgordon17/summon-claude@d05f2b9577aeb0bec384b48733eb7b609aea6e7d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/wgordon17
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@d05f2b9577aeb0bec384b48733eb7b609aea6e7d -
Trigger Event:
release
-
Statement type:
File details
Details for the file summon_claude-0.1.0-py3-none-any.whl.
File metadata
- Download URL: summon_claude-0.1.0-py3-none-any.whl
- Upload date:
- Size: 56.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
004032796da584c28afd0d1ff8a548711c1c7c2b7decb77ed6da8e0b5d37d7d1
|
|
| MD5 |
9a042f87db272b6adc4c7bd7299abe1e
|
|
| BLAKE2b-256 |
cf57a7b6101d2f412c94045149ab9107e0f204379b5cf647d2ae7f5f69476f4b
|
Provenance
The following attestation bundles were made for summon_claude-0.1.0-py3-none-any.whl:
Publisher:
publish.yaml on wgordon17/summon-claude
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
summon_claude-0.1.0-py3-none-any.whl -
Subject digest:
004032796da584c28afd0d1ff8a548711c1c7c2b7decb77ed6da8e0b5d37d7d1 - Sigstore transparency entry: 992577126
- Sigstore integration time:
-
Permalink:
wgordon17/summon-claude@d05f2b9577aeb0bec384b48733eb7b609aea6e7d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/wgordon17
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@d05f2b9577aeb0bec384b48733eb7b609aea6e7d -
Trigger Event:
release
-
Statement type: