# Discord-Claude Gateway An event-driven agent runtime that connects Discord to Claude via the [Claude Agent SDK](https://docs.anthropic.com/en/docs/agent-sdk/overview). Inspired by [OpenClaw](https://github.com/nichochar/open-claw)'s architecture — a gateway in front of an agent runtime with markdown-based personality, memory, and scheduled behaviors. ## How It Works ``` Discord Users ──► Discord Bot ──► Event Queue ──► Agent Runtime ──► Claude Agent SDK ▲ │ Heartbeats ──────────┤ │ Cron Jobs ───────────┤ ┌─────────────────────┘ Hooks ───────────────┘ ▼ Markdown Config Files (soul, identity, memory, etc.) ``` All inputs — Discord messages, heartbeat timers, cron jobs, lifecycle hooks — enter a unified event queue. The agent runtime reads your markdown config files fresh on each event, assembles a dynamic system prompt, and calls the Claude Agent SDK. The agent can write back to `memory.md` to persist facts across sessions. ## Prerequisites - **Node.js** 18+ - **Claude Code CLI** — [Install Claude Code](https://docs.anthropic.com/en/docs/claude-code/getting-started) and sign in with your subscription - **Discord Bot Token** — [Create a bot](https://discord.com/developers/applications) with Message Content Intent enabled ## Quick Start ```bash # Install dependencies npm install # Make sure Claude Code CLI is installed and you're signed in claude --version # Set required environment variables export DISCORD_BOT_TOKEN=your-discord-bot-token # Create config directory with persona files mkdir config ``` Create at minimum `config/soul.md` and `config/identity.md`: ```bash # config/identity.md echo "# Identity - **Name:** Aetheel - **Vibe:** Helpful, sharp, slightly witty - **Emoji:** ⚡" > config/identity.md # config/soul.md echo "# Soul Be genuinely helpful. Have opinions. Be resourceful before asking. Earn trust through competence." > config/soul.md ``` ```bash # Start the gateway npm run dev ``` ## Configuration All settings are via environment variables: | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `DISCORD_BOT_TOKEN` | Yes | — | Discord bot token | | `CLAUDE_CLI_PATH` | No | `claude` | Path to the Claude Code CLI binary | | `ALLOWED_TOOLS` | No | `Read,Write,Edit,Glob,Grep,WebSearch,WebFetch` | Comma-separated Claude Code tools | | `PERMISSION_MODE` | No | `bypassPermissions` | Claude Code permission mode | | `QUERY_TIMEOUT_MS` | No | `120000` | Query timeout in milliseconds | | `MAX_CONCURRENT_QUERIES` | No | `5` | Max simultaneous Claude queries | | `CONFIG_DIR` | No | `./config` | Path to markdown config directory | | `MAX_QUEUE_DEPTH` | No | `100` | Max events in the queue | | `OUTPUT_CHANNEL_ID` | No | — | Discord channel for heartbeat/cron output | ## Markdown Config Files Place these in your `CONFIG_DIR` (default: `./config/`). The gateway reads them fresh on every event — edit them anytime, no restart needed. | File | Purpose | Required | |------|---------|----------| | `identity.md` | Agent name, role, specialization | Yes | | `soul.md` | Personality, tone, values, behavior defaults | Yes | | `agents.md` | Operating rules, safety boundaries, cron jobs, hooks | No | | `user.md` | Info about you: name, preferences, context | No | | `memory.md` | Long-term memory (agent can write to this) | No (auto-created) | | `tools.md` | Tool configs, API notes, usage limits | No | | `heartbeat.md` | Proactive check definitions | No | | `boot.md` | Bootstrap configuration | No | Missing optional files are created with default headers on first run. ### Heartbeat Config (`heartbeat.md`) Define proactive checks the agent runs on a timer: ```markdown ## check-email Interval: 1800 Instruction: Check my inbox for anything urgent. If nothing, reply HEARTBEAT_OK. ## check-calendar Interval: 3600 Instruction: Review upcoming calendar events in the next 24 hours. ``` Interval is in seconds (minimum 60). ### Cron Jobs (in `agents.md`) Define scheduled tasks with cron expressions: ```markdown ## Cron Jobs ### morning-briefing Cron: 0 9 * * * Instruction: Good morning! Check email, review today's calendar, and give me a brief summary. ### weekly-review Cron: 0 15 * * 1 Instruction: Review the week's calendar and flag any conflicts. ``` ### Hooks (in `agents.md`) Define lifecycle hook instructions: ```markdown ## Hooks ### startup Instruction: Read memory.md and greet the user. ### shutdown Instruction: Save any important context to memory.md before shutting down. ``` ## Discord Commands | Command | Description | |---------|-------------| | `@bot ` | Send a prompt by mentioning the bot | | `/claude ` | Send a prompt via slash command | | `/claude-reset` | Reset the conversation session in the current channel | ## Architecture The system has 5 input types (inspired by OpenClaw): 1. **Messages** — Discord mentions and slash commands 2. **Heartbeats** — Timer-based proactive checks 3. **Cron Jobs** — Scheduled events with cron expressions 4. **Hooks** — Internal lifecycle triggers (startup, shutdown, agent_begin, agent_stop) 5. **Webhooks** — External system events (planned) All inputs enter a unified FIFO event queue → processed sequentially by the agent runtime → state persists to markdown files → loop continues. ## Project Structure ``` src/ ├── index.ts # Entry point ├── gateway-core.ts # Main orchestrator ├── config.ts # Environment variable loader ├── discord-bot.ts # Discord.js wrapper ├── event-queue.ts # Unified FIFO event queue ├── agent-runtime.ts # Core processing engine ├── markdown-config-loader.ts # Reads config files from disk ├── system-prompt-assembler.ts# Assembles system prompt from configs ├── session-manager.ts # Channel-to-session bindings ├── channel-queue.ts # Per-channel sequential processing ├── response-formatter.ts # Message splitting for Discord's 2000 char limit ├── error-formatter.ts # Safe error formatting ├── heartbeat-scheduler.ts # Recurring timer events ├── cron-scheduler.ts # Cron-expression scheduled events ├── hook-manager.ts # Lifecycle hook events ├── bootstrap-manager.ts # First-run file validation/creation └── shutdown-handler.ts # Graceful SIGTERM/SIGINT handling ``` ## Development ```bash # Run tests npm test # Run in dev mode npm run dev # Build npm run build # Start production npm start ``` ## Claude Code CLI vs API Key This gateway uses the **Claude Code CLI** (`claude -p`) instead of the Anthropic API directly. This means: - You use your existing **Claude Code subscription** — no separate API key needed - Just sign in with `claude` in your terminal and you're good to go - The gateway shells out to `claude -p "prompt" --output-format json` for each query - Set `CLAUDE_CLI_PATH` if `claude` isn't in your PATH ## License MIT