AI-powered Slack bot that uses Claude to help teams manage GitHub issues through conversation. Mention the bot in a Slack thread and it will read the discussion, interact with GitHub, and reply with results.
- Creates GitHub issues from Slack thread discussions
- Searches for related issues and PRs
- Triages and labels issues
- Summarizes threads and answers questions about repositories
- Knows common repository aliases via a built-in skill (e.g.
@bot create an issue in mobile) - Remembers context within Slack threads (session persistence)
- Learns from every run and adapts over time (memory system)
- Node.js 20+
- A Slack app configured for Socket Mode with an
app_mentionevent subscription - GitHub personal access token
- Anthropic OAuth refresh token
npm ci
cp .env.example .env
# Fill in your credentials in .env# Production
npm start
# Development (watch mode)
npm run dev
# CLI mode for local testing (no Slack required)
npm run cli # interactive REPL
npm run cli -- "Create an issue" # one-shot mode
npm run cli -- --dry-run "Describe plan" # one-shot, dry runSee .env.example for all available options. Key variables:
| Variable | Required | Description |
|---|---|---|
SLACK_BOT_TOKEN |
Yes | Bot token (xoxb-...) |
SLACK_APP_TOKEN |
Yes | App-level token for Socket Mode (xapp-...) |
GITHUB_TOKEN |
Yes | GitHub PAT for gh CLI |
ANTHROPIC_OAUTH_REFRESH_TOKEN |
No* | Anthropic OAuth refresh token (see Auth section) |
MODEL |
No | Model override (default: claude-sonnet-4-5). PR reviews always use claude-opus-4-6 regardless of this setting. |
MAX_CONCURRENT_AGENTS |
No | Max parallel agent runs (default: 3) |
UPSTASH_REDIS_REST_URL |
No | Upstash Redis URL for OAuth token persistence |
UPSTASH_REDIS_REST_TOKEN |
No | Upstash Redis token |
LOG_CHANNEL_ID |
No | Slack channel ID for audit logging |
HEALTH_PORT |
No | Port for health check endpoint (GET /health/live) |
MEMORY_REPO |
No | GitHub repo for persistent memory (e.g. owner/claw-memory) |
*Required for first-time setup if no .auth.json exists yet.
All Anthropic auth uses OAuth — there is no API key path. The OAuth flow works like this:
- A refresh token is exchanged for a short-lived access token on each API call.
- The SDK may rotate the refresh token after use, so the original token becomes invalid.
- The current auth state (refresh + access + expiry) is persisted in
.auth.json.
Getting started:
- First run — set
ANTHROPIC_OAUTH_REFRESH_TOKENin.env. The bot writes.auth.jsonon startup and uses that going forward. - Existing session — copy
.auth.jsonfrom another pi-agent or OpenDCL session into the project root. No env var needed. - CLI — works if
.auth.jsonexists (npm run cli). No env var needed.
Why .auth.json matters: because refresh tokens rotate on use, the file is the source of truth. The env var is only a seed for first-time setup.
Why Redis: container restarts lose the file, so the original env var token may already be expired. When Upstash Redis is configured (UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN):
- On startup — the bot loads the latest auth state from Redis instead of the env var.
- After each rotation — the bot syncs the new state back to Redis.
This keeps the bot resilient to restarts without manual token re-provisioning.
When MEMORY_REPO is set, memory files are backed by a GitHub repository:
- On startup — the repo is cloned (or pulled if already present)
- After each run — the agent commits and pushes changes as part of its memory save step
- Conflicts — resolved by the agent during
git pull --rebase(it understands both git and the content)
Without MEMORY_REPO, the bot works normally but memory doesn't survive container restarts. Sessions are always ephemeral.
docker build -t slack-issue-bot .
docker run --env-file .env slack-issue-botSet HEALTH_PORT=5000 (and expose the port) to enable the health check endpoint.
src/
index.ts Entry point — startup, shutdown, git clone
slack.ts Slack event handlers, thread fetching, message formatting
agent.ts Session management, memory loading, pi-coding-agent
prompt.ts Prompt builder (extracted for testability)
config.ts Environment variable loading
concurrency.ts Agent scheduler with queue management and drain
memory.ts Memory loading, save prompt, qmd index, git clone/pull
cli.ts CLI interface for local testing (REPL + one-shot)
health.ts Health check endpoint
test/ Unit tests (node:test)
prompts/
system.md System prompt for the Claude agent
skills/ Agent skill definitions (create-issue, create-skill, github, memory-search, mobile-project, pr-review, reflect, repos, triage)