Skip to content

EndemicMedia/slack-llm-runner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Slack LLM Runner πŸ€–

Run CLI tools (Claude Code, Kimi, shell commands) from Slack with smart output filtering and full session logging.

Node.js Version TypeScript License: MIT

✨ What It Does

Slack CLI Wrapper is a bidirectional bridge between Slack and CLI tools running on your local machine. It lets you:

  • πŸš€ Execute commands from Slack: run: docker ps, claude: refactor auth.js, kimi: explain this code
  • πŸ’¬ Interact with AI CLIs - Have full conversations with Claude Code or Kimi through Slack threads
  • πŸ“Š Run scheduled jobs - Cron jobs that execute commands and report to Slack
  • πŸ“ Access full logs - Complete session output is always logged locally, retrievable on demand
  • 🧠 Smart filtering - AI CLIs use "envelope" markers to decide what gets posted to Slack (no noise!)

Demo

[Slack #dev-channel]

Alice:  claude: write tests for utils.js

Bot:    πŸš€ Session started (claude code) β€” logs: session_abc123.log

        [Claude reads files, writes tests, runs them β€” 
         ~200 lines of output goes to log file only]

Bot:    βœ… Refactor complete. All 47 tests pass.
        Coverage: 94% on utils.js.

Bot:    βœ… Session complete (exit code 0)

Alice:  /logs
Bot:    πŸ“Ž session_abc123.log (2.1 KB uploaded)

πŸ—οΈ Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     WebSocket      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Slack     │◀══════════════════▢│  Slack CLI Wrapper (Node.js)               β”‚
β”‚  (Cloud)    β”‚    (Socket Mode)   β”‚                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                                   β”‚  β”‚   Slack     β”‚    β”‚   CLI Runner      β”‚  β”‚
                                   β”‚  β”‚  Listener   │───▢│   (node-pty)      β”‚  β”‚
                                   β”‚  β”‚  (Bolt)     │◀───│                   β”‚  β”‚
                                   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                   β”‚                               β”‚            β”‚
                                   β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
                                   β”‚                    β–Ό                    β–Ό   β”‚
                                   β”‚           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                                   β”‚           β”‚  Envelope   β”‚      β”‚  Full    β”‚ β”‚
                                   β”‚           β”‚  Parser     β”‚      β”‚ Output   β”‚ β”‚
                                   β”‚           β”‚  (LLM mode) β”‚      β”‚ Streamer β”‚ β”‚
                                   β”‚           β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚
                                   β”‚                  β”‚                   β”‚      β”‚
                                   β”‚         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”‚
                                   β”‚         β”‚     Slack       β”‚  β”‚   Slack    β”‚ β”‚
                                   β”‚         β”‚   (enveloped)   β”‚  β”‚  (all out) β”‚ β”‚
                                   β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Two-Track Output Model:

  • Track 1: Log β†’ Everything is written to logs/sessions/<sessionId>.log
  • Track 2: Slack β†’ AI CLIs use envelope markers; shell commands stream everything

πŸš€ Quick Start

Prerequisites

  • Node.js 20+
  • A Slack workspace where you can create apps
  • Bash shell (Windows: Git Bash or WSL)
  • (Optional) claude CLI or kimi CLI for AI features

1. Clone & Install

git clone https://github.com/yourusername/slack-cli-wrapper.git
cd slack-cli-wrapper
npm install

2. Create Slack App

  1. Go to api.slack.com/apps β†’ Create New App
  2. Enable Socket Mode (toggle ON)
  3. Generate an App-Level Token with scope connections:write
  4. Add Bot Token Scopes: chat:write, channels:read, users:read
  5. Subscribe to Bot Events: message.channels
  6. Install to Workspace

3. Configure Environment

cp .env.example .env

Edit .env:

SLACK_APP_TOKEN=xapp-...            # From step 2
SLACK_BOT_TOKEN=xoxb-...            # From step 2
SLACK_LISTEN_CHANNELS=C0123456789   # Channel ID(s) to listen in
ALLOWED_USER_IDS=U0123456789        # Your Slack user ID

4. Configure Commands

Edit config/commands.yaml:

commands:
  - prefix: "run"
    binary: "bash"
    args: ["-c"]
    mode: one-shot
    envelope: false
    description: "Run a shell command"

  - prefix: "claude"
    binary: "claude"          # or full path
    args: ["--verbose"]
    promptFlag: "-p"
    sessionIdFlag: "--session-id"  # Create new session
    resumeFlag: "--resume"         # Continue existing session
    mode: one-shot
    envelope: true
    description: "Run Claude Code"

5. Run

npm run dev        # Development with hot reload
# or
npm run build      # Build for production
npm start          # Run production build

πŸ’¬ Usage

Shell Commands (Full Output)

run: docker ps
run: npm test
run: ls -la

Output streams directly to Slack in real-time.

AI CLI Sessions (Envelope Filtered)

claude: refactor the auth module
kimi: explain this regex

The AI sees a system prompt that teaches it to use envelope markers:

<<<SLACK:progress>>>
Analyzed auth module. Found 3 functions to refactor.
<<<END_SLACK>>>

Only enveloped messages appear in Slack. Full output is in the log.

Thread Follow-Ups & Session Continuation

Reply in the thread to continue the conversation with context preserved:

Alice: claude: my name is Alice
Bot:   πŸš€ Session started β€” Run Claude Code
       βœ… Session complete (exit code 0)

Alice [in thread]: what is my name?
      β†’ Spawns continuation with --resume, Claude remembers "Alice"

How it works:

  • Kimi: Uses -S <session-id> flag (same for create and resume)
  • Claude: Uses --session-id <uuid> for first call, --resume <uuid> for follow-ups
  • Session IDs: Deterministically generated from slack-<channel>-<thread> so same thread always maps to same session

Control Commands

Command Description
/status List active sessions
/stop <id> Kill a session
/logs Upload most recent session log
/logs <id> Upload specific session log
/logs tail 50 Show last 50 lines
/logs list List recent sessions
/help Show available commands

βš™οΈ Configuration

Environment Variables

Variable Description
SLACK_APP_TOKEN Socket Mode connection token (xapp-...)
SLACK_BOT_TOKEN Web API token (xoxb-...)
SLACK_LISTEN_CHANNELS Comma-separated channel IDs
ALLOWED_USER_IDS Comma-separated user IDs allowed to run commands
SESSION_TIMEOUT_MINUTES Max session lifetime (default: 30)
OUTPUT_FLUSH_INTERVAL_MS How often to push output (default: 2000)
ENVELOPE_ACTIVATION_DELAY_MS Delay before parsing envelopes (default: 1500)

Authorization (config/authorization.yaml)

rules:
  - channels: ["C0123456789"]
    users: ["*"]                    # Any user in ALLOWED_USER_IDS
    allowed_prefixes: ["claude", "kimi", "run"]

  - channels: ["C9876543210"]
    users: ["U0123456789"]          # Only specific user
    allowed_prefixes: ["run"]       # Only shell commands

Scheduled Jobs (config/jobs.yaml)

jobs:
  - name: "daily-backup-check"
    cron: "0 6 * * *"
    command: "bash scripts/backup-check.sh"
    channel: "C0123456789"
    cwd: "/path/to/project"

πŸ”§ Development

Project Structure

slack-cli-wrapper/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ cli/              # PTY spawn, session lifecycle
β”‚   β”œβ”€β”€ commands/         # Command parsing & routing
β”‚   β”œβ”€β”€ streaming/        # Envelope parser, streamer, log writer
β”‚   β”œβ”€β”€ scheduler/        # Cron job scheduling
β”‚   β”œβ”€β”€ security/         # Authorization & command filtering
β”‚   β”œβ”€β”€ slack/            # Bolt app, listeners, reporter
β”‚   └── utils/            # Config, logger, formatting
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ prompts/          # System prompts for LLMs
β”‚   β”œβ”€β”€ authorization.yaml
β”‚   β”œβ”€β”€ commands.yaml
β”‚   └── jobs.yaml
β”œβ”€β”€ scripts/debug/        # Manual debugging utilities
└── test/                 # Automated tests

Scripts

npm run dev              # Development mode
npm run build            # Compile TypeScript
npm start                # Production mode
npm test                 # Run unit tests
npm run test:lifecycle   # Run E2E session lifecycle tests
npm run restart          # Kill all node processes and restart

Running Tests

# Unit tests for process handle
npm test

# E2E tests for session lifecycle
npm run test:lifecycle

# Integration test
node --import tsx --test test/integration.test.ts

πŸ”’ Security

  • No tokens in code - All secrets in .env (gitignored)
  • User allowlist - Only configured Slack users can run commands
  • Channel restriction - Bot only listens in configured channels
  • Command filtering - Block dangerous patterns (rm -rf, etc.)
  • Audit logging - Every command logged with user ID, timestamp, exit code
  • Session timeouts - Prevent runaway processes

Security Best Practices

  1. Keep .env file secure and never commit it
  2. Use specific user IDs in ALLOWED_USER_IDS, not *
  3. Restrict allowed_prefixes per channel as needed
  4. Review audit logs regularly: logs/audit.log
  5. Run with minimal permissions (don't run as root)

🀝 Contributing

Contributions are welcome! Here's how to get started:

Development Setup

# Fork and clone
git clone https://github.com/YOUR_USERNAME/slack-cli-wrapper.git
cd slack-cli-wrapper

# Install dependencies
npm install

# Copy env template
cp .env.example .env
# Edit .env with your test Slack app tokens

# Run in dev mode
npm run dev

Contribution Guidelines

  1. Fork the repository
  2. Create a branch for your feature: git checkout -b feature/amazing-feature
  3. Make your changes with clear, focused commits
  4. Add tests if applicable
  5. Update documentation if needed
  6. Submit a Pull Request with a clear description

Code Style

  • TypeScript with strict mode enabled
  • Use meaningful variable names
  • Add JSDoc comments for public APIs
  • Keep functions focused and small
  • Handle errors gracefully

Areas for Contribution

  • Additional CLI integrations
  • Better output formatting
  • Web dashboard for session logs
  • More envelope types
  • Plugin system for custom handlers
  • Docker support
  • Windows/WSL improvements

πŸ“š Documentation

πŸ› Troubleshooting

Bot won't connect

# Kill all node processes
npm run clean

# Wait 30 seconds for Slack to release connection
# Then restart
npm run dev

No output from commands

  • Check that bash.exe is in your PATH (Windows)
  • Verify session logs: logs/sessions/*.log
  • Run E2E tests: npm run test:lifecycle

Socket Mode disconnects

Slack only allows one connection per app token. If you have multiple instances running:

  1. Kill all node processes: npm run clean
  2. Wait 30 seconds
  3. Restart the bot

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • Built with Slack Bolt framework
  • Uses node-pty for PTY support
  • Inspired by the need for less noisy AI CLI integrations

Made with ❀️ for cleaner Slack integrations

About

Execute LLM prompts and CLI commands from Slack with intelligent output filtering and full session logging.

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors