Files
aetheel-2/README.md

234 lines
8.7 KiB
Markdown

# Aetheel — Discord-Claude Gateway
An event-driven AI agent runtime that connects Discord to Claude Code CLI. Inspired by [OpenClaw](https://github.com/nichochar/open-claw)'s architecture — a gateway in front of an agent runtime with markdown-based personality, memory, scheduled behaviors, and proactive messaging.
## How It Works
```
Discord Users ──► Discord Bot ──► Event Queue ──► Agent Runtime ──► Claude Code CLI
▲ │
Heartbeats ──────────┤ │
Cron Jobs ───────────┤ ┌─────────────────────┘
Hooks ───────────────┘ ▼
IPC Watcher ───────────── Markdown Config Files
(CLAUDE.md, memory.md, 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 Code CLI. The agent can write back to `memory.md` to persist facts across sessions, and send proactive messages via the IPC system.
Uses your existing Claude Code subscription — no API key needed.
## Prerequisites
- Node.js 18+
- Claude Code CLI installed and signed in (`npm install -g @anthropic-ai/claude-code && claude`)
- A Discord bot token ([create one here](https://discord.com/developers/applications)) with Message Content Intent enabled
## Quick Start
```bash
git clone <your-repo-url>
cd aetheel-2
npm install
cp .env.example .env # Edit with your Discord bot token
mkdir -p config
# Create config/CLAUDE.md with your persona (see Setup section)
npm run dev
```
Or run the interactive setup:
```bash
bash scripts/setup.sh
```
## Configuration
### Environment Variables
Create a `.env` file in the project root (auto-loaded via dotenv):
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `DISCORD_BOT_TOKEN` | Yes | — | Discord bot token |
| `OUTPUT_CHANNEL_ID` | No | — | Discord channel for heartbeat/cron/hook output |
| `CLAUDE_CLI_PATH` | No | `claude` | Path to the Claude Code CLI binary |
| `CONFIG_DIR` | No | `./config` | Path to markdown config directory |
| `ALLOWED_TOOLS` | No | `Read,Write,Edit,Glob,Grep,WebSearch,WebFetch` | Comma-separated tools the agent can use |
| `PERMISSION_MODE` | No | `bypassPermissions` | Claude Code permission mode |
| `QUERY_TIMEOUT_MS` | No | `120000` | Max time per query (ms) |
| `MAX_CONCURRENT_QUERIES` | No | `5` | Max simultaneous queries |
| `MAX_QUEUE_DEPTH` | No | `100` | Max events in the queue |
| `IDLE_SESSION_TIMEOUT_MS` | No | `1800000` | Session idle timeout (30 min) |
| `LOG_LEVEL` | No | `info` | Log level: debug, info, warn, error |
### Markdown Config Files
Place these in `CONFIG_DIR` (default: `./config/`):
| File | Purpose | Required |
|------|---------|----------|
| `CLAUDE.md` | Persona: identity, personality, user context, tools | Yes |
| `agents.md` | Operating rules, cron jobs, hooks (parsed at startup) | No |
| `memory.md` | Long-term memory (agent-writable) | No (auto-created) |
| `heartbeat.md` | Proactive check definitions (parsed at startup) | No |
The gateway reads `CLAUDE.md` and `memory.md` fresh on every event — edit them anytime. `agents.md` and `heartbeat.md` are parsed at startup for timers, so restart after editing those.
### Skills
Drop skill files into `config/skills/{name}/SKILL.md` and they're automatically loaded into the system prompt:
```
config/skills/
├── web-research/
│ └── SKILL.md → "When asked to research, use WebSearch..."
└── code-review/
└── SKILL.md → "When reviewing code, focus on..."
```
## Features
### Discord Integration
- Mention the bot (`@Aetheel hi`) or use `/claude` slash command
- `/claude-reset` to start a fresh conversation
- Responses auto-split at 2000 chars with code block preservation
- Typing indicators while processing
### Session Management
- Per-channel conversation sessions with Claude Code CLI `--resume`
- Sessions persist to `config/sessions.json` (survive restarts)
- Auto-cleanup of idle sessions after 30 minutes (configurable)
### Heartbeats (Timer Events)
Define in `config/heartbeat.md`:
```markdown
## check-email
Interval: 1800
Instruction: Check my inbox for anything urgent.
```
### Cron Jobs (Scheduled Events)
Define in `config/agents.md`:
```markdown
## Cron Jobs
### morning-briefing
Cron: 0 8 * * *
Instruction: Good morning! Search for the latest AI news and post a summary.
```
### Lifecycle Hooks
Define in `config/agents.md`:
```markdown
## Hooks
### startup
Instruction: Say hello, you just came online.
### shutdown
Instruction: Save important context to memory.md.
```
### Proactive Messaging (IPC)
The agent can send messages to any Discord channel by writing JSON files to `config/ipc/outbound/`:
```json
{"channelId": "123456789", "text": "Hey, found something interesting!"}
```
The gateway polls every 2 seconds and delivers the message.
### Message History
All inbound/outbound messages stored per channel in `config/messages/{channelId}.json`. Max 100 messages per channel, auto-trimmed.
### Conversation Archiving
Every exchange saved as readable markdown in `config/conversations/{channelId}/{YYYY-MM-DD}.md`.
### Retry with Backoff
Claude CLI calls retry 3 times with exponential backoff (5s, 10s, 20s) on transient errors. Session corruption errors fail immediately.
### Structured Logging
Pino-based structured JSON logging. Set `LOG_LEVEL=debug` for verbose output. Pretty-printed in dev, JSON in production (`NODE_ENV=production`).
## Deployment
### systemd (recommended for Linux servers)
```bash
sudo bash scripts/setup.sh # Creates .env, config/, and systemd service
```
Or manually:
```bash
sudo cp scripts/aetheel.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable aetheel
sudo systemctl start aetheel
# View logs
sudo journalctl -u aetheel -f
```
### PM2
```bash
npm run build
pm2 start dist/index.js --name aetheel
pm2 save
```
### Dev mode
```bash
npm run dev
```
## Project Structure
```
src/
├── index.ts # Entry point (loads .env)
├── gateway-core.ts # Main orchestrator
├── config.ts # Environment variable loader
├── logger.ts # Pino structured logger
├── discord-bot.ts # Discord.js wrapper
├── event-queue.ts # Unified FIFO event queue
├── agent-runtime.ts # Core engine: reads configs, spawns CLI, streams output
├── markdown-config-loader.ts # Reads CLAUDE.md, agents.md, memory.md
├── system-prompt-assembler.ts # Assembles system prompt with sections
├── skills-loader.ts # Loads skills from config/skills/*/SKILL.md
├── session-manager.ts # Channel → session ID (persisted, idle cleanup)
├── message-history.ts # Per-channel message storage
├── conversation-archiver.ts # Markdown conversation logs
├── ipc-watcher.ts # Polls ipc/outbound/ for proactive messages
├── response-formatter.ts # Splits long text for Discord's 2000 char limit
├── error-formatter.ts # Sanitizes errors (strips keys, paths, stacks)
├── heartbeat-scheduler.ts # Recurring timer events
├── cron-scheduler.ts # node-cron scheduled events
├── hook-manager.ts # Lifecycle hooks
├── bootstrap-manager.ts # First-run file validation/creation
├── channel-queue.ts # Per-channel sequential processing
└── shutdown-handler.ts # Graceful SIGTERM/SIGINT handling
config/ # Agent workspace (gitignored)
├── CLAUDE.md # Persona
├── agents.md # Rules, cron, hooks
├── memory.md # Long-term memory (agent-writable)
├── heartbeat.md # Heartbeat checks
├── sessions.json # Session persistence (auto)
├── messages/ # Message history (auto)
├── conversations/ # Conversation archives (auto)
├── ipc/outbound/ # Proactive message queue (auto)
├── skills/ # Skill definitions
└── news/ # Example: agent-created content
```
## Development
```bash
npm test # Run tests (85 passing)
npm run dev # Dev mode with tsx
npm run build # Compile TypeScript
npm start # Run compiled JS
```
## License
MIT