Hermes
Control Claude Code from Slack. Each channel is a repo, each Slack thread is a session.
Access Claude from anywhere — start on your laptop, continue on your phone. Sessions persist across messages and restarts, local CLI sessions auto-sync to Slack, and fine-grained tool permissions control what Claude can run. Zero infrastructure needed (Socket Mode, no webhooks).
Quick Start
# Install
# Set up Slack app (see below), then:
In Slack, type in a repo channel:
fix the failing tests in the auth module
Hermes replies in a Slack thread. Reply to continue — full history is preserved.
Features
- 🔄 Persistent sessions — Conversations survive restarts, resume automatically
- 📱 Mobile access — Control Claude from your phone via Slack
- 🔗 Local sync — Start sessions with
claudeCLI, continue in Slack - 🔒 Fine-grained permissions — Control which tools Claude can use per repo
- 👥 Team-friendly — Deploy on a VPS for shared access
- ⚡ Zero infrastructure — Socket Mode (no webhooks, no public URLs)
- 🧵 Thread-based — One channel = one repo, one Slack thread = one session
How It Works
┌─────────┐ ┌─────────┐ ┌─────────────┐
│ Slack │ ◄─── Socket Mode──►│ Hermes │ ◄─── stdin/out ───►│ Claude CLI │
│ Channel │ │ │ │ Process │
└─────────┘ └─────────┘ └───────┬─────┘
│ │ │
│ 1. User types message │ │
├──────────────────────────────► │
│ │ 2. Spawn agent │
│ ├─────────────────────────────────►
│ │ │
│ │ 3. Stream events (tools, text) │
│ │◄────────────────────────────────┤
│ 4. Post results in Slack thread │
│◄─────────────────────────────┤ │
│ │ │
│ 5. User replies in Slack thread ▼
├──────────────────────────────► ┌──────────┐
│ │ 6. Resume session │ Local │
│ ├──────────────────────────►│ Git Repo │
│ 7. Continue conversation │ └──────────┘
│◄─────────────────────────────┘
Installation
Prerequisites
- Rust (see
rust-versioninCargo.tomlfor MSRV) - Claude Code CLI installed and authenticated
- A Slack workspace where you can create apps
Slack App Setup
- Go to api.slack.com/apps → Create New App → From an app manifest
- Pick your workspace
- Paste
slack-manifest.jsonfrom this repo - Click Create
- Install to Workspace (OAuth & Permissions)
- Copy Bot Token (
xoxb-...) from OAuth & Permissions - Generate App Token (
xapp-...) from Basic Information → App-Level Tokens → addconnections:writescope - Get your Slack User ID — Profile → three dots → Copy member ID
Configuration
1. Slack tokens:
Edit .env:
SLACK_APP_TOKEN=xapp-1-...
SLACK_BOT_TOKEN=xoxb-...
2. Configure repos:
Edit config.toml:
[]
= ["U01234567"] # Your Slack user ID
[]
= "batch" # or "live" for real-time
= ["Read", "Glob", "Grep", "WebSearch"]
[]
= "/absolute/path/to/my-project"
= ["Edit", "Write", "Bash(cargo *)"]
3. Run:
Hermes auto-creates channels from repo names (e.g., repos.backend → #backend).
Usage
Commands
In threads:
!status— Show session info!stop— Stop session!model— Show current model!model opus— Switch to Opus (also:sonnet,haiku)!execute— Run last plan with fresh context
Slash commands:
/claude sessions— List active sessions/claude help— Show help
Local Session Sync
Run claude locally in a configured repo, and Hermes auto-detects it:
Local session detected (branch: main)
> fix the tests
Reply in the Slack thread to continue.
To disable sync globally or per-repo:
[]
= false # disable for all repos
[]
= true # re-enable for this repo only
Security & Permissions
User allowlist — Only users in allowed_users can interact.
Tool permissions — Claude can only run pre-approved tools:
- Global (all repos):
Read,Glob,Grep,WebSearch— safe, read-only - Per-repo:
Edit,Write,Bash(cargo *)— scoped to specific repos
Example: frontend repo allows Bash(npm *) but not Bash(rm *).
Audit trail — All commands visible in Slack threads.
Team Usage
Personal use: Run on your laptop, message from your phone.
Team use: Run on a VPS. Multiple people can use Claude, conversations are shared in Slack.
Comparison
| Feature | Hermes | OpenClaw / Alternatives |
|---|---|---|
| Infrastructure | Socket Mode — laptop or VPS, no webhooks | Requires public URLs, server deployment |
| Mental model | Channel = repo, Slack thread = session | Varies |
| Implementation | Uses Claude CLI — gets updates free | Often reimplements integration |
| Local + Remote | Auto-syncs local sessions | Typically Slack-only or CLI-only |
| Security | Per-repo tool permissions | Often all-or-nothing |
Troubleshooting
"Failed to spawn claude CLI"
→ Install: npm install -g @anthropic-ai/claude-code
→ Verify: claude --version
"Socket Mode connection failed"
→ Check SLACK_APP_TOKEN starts with xapp- and has connections:write scope
→ Check SLACK_BOT_TOKEN starts with xoxb-
→ Enable Socket Mode in app settings
Bot doesn't respond
→ Check allowed_users includes your Slack user ID
→ Verify bot is in the channel
Sessions not resuming
→ Ensure sessions.json is writable
→ Agent processes killed on shutdown, auto-recover on next message
Architecture
- Socket Mode — No public URL, works on laptop or VPS
- Agent trait — Extensible backend (Claude Code implemented)
- Session persistence —
sessions.jsonsurvives restarts - Concurrency guard — One agent per Slack thread
- Local session sync — Filesystem watcher imports CLI sessions
src/
main.rs Socket Mode setup, shutdown handling
config.rs Config loading and validation
session.rs Session persistence (sessions.json)
sync.rs Local CLI session sync (notify crate)
slack/ Slack API, message handlers, formatting
agent/ Agent trait, Claude CLI integration, protocol parser
Contributing
Contributions welcome!
Before submitting:
Guidelines:
- Use
thiserrorfor errors - Add tests for new features
- Keep commits focused
Open PRs against main. For bugs, include steps to reproduce and your Rust version.
License
MIT — see LICENSE