# Hermes
[](https://github.com/jbyoung12/hermes-bot/actions)
[](LICENSE)
[](https://www.rust-lang.org)
**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
```bash
# Install
cargo install hermes-bot
# Set up Slack app (see below), then:
cp .env.example .env
cp config.toml.example config.toml
hermes
```
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 `claude` CLI, 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](https://rustup.rs/) (see `rust-version` in `Cargo.toml` for MSRV)
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
- A Slack workspace where you can create apps
### Slack App Setup
1. Go to [api.slack.com/apps](https://api.slack.com/apps) β **Create New App** β **From an app manifest**
2. Pick your workspace
3. Paste `slack-manifest.json` from this repo
4. Click **Create**
5. **Install to Workspace** (OAuth & Permissions)
6. Copy **Bot Token** (`xoxb-...`) from OAuth & Permissions
7. Generate **App Token** (`xapp-...`) from Basic Information β App-Level Tokens β add `connections:write` scope
8. **Get your Slack User ID** β Profile β three dots β **Copy member ID**
### Configuration
**1. Slack tokens:**
```bash
cp .env.example .env
```
Edit `.env`:
```env
SLACK_APP_TOKEN=xapp-1-...
SLACK_BOT_TOKEN=xoxb-...
```
**2. Configure repos:**
```bash
cp config.toml.example config.toml
```
Edit `config.toml`:
```toml
[slack]
allowed_users = ["U01234567"] # Your Slack user ID
[defaults]
streaming_mode = "batch" # or "live" for real-time
allowed_tools = ["Read", "Glob", "Grep", "WebSearch"]
[repos.my-project]
path = "/absolute/path/to/my-project"
allowed_tools = ["Edit", "Write", "Bash(cargo *)"]
```
**3. Run:**
```bash
cargo run # or 'hermes' if installed
```
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:
```toml
[defaults]
sync_local_sessions = false # disable for all repos
[repos.my-project]
sync_local_sessions = 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
| **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.json` survives 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!
```bash
git clone https://github.com/jbyoung12/hermes-bot.git
cd hermes-bot
cp .env.example .env
cp config.toml.example config.toml
cargo test
```
**Before submitting:**
```bash
cargo fmt
cargo clippy -- -D warnings
cargo test
```
**Guidelines:**
- Use `thiserror` for 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](LICENSE)