# Aetheel — AI Agent Runtime with Mission Control An event-driven AI agent runtime that connects Discord to your choice of coding agent CLI — **Claude Code**, **Codex**, **Gemini CLI**, **OpenCode**, or **Pi** — with an embedded **Mission Control dashboard** for real-time monitoring, second brain knowledge management, task tracking, and content curation. 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 ──► Backend Adapter ▲ │ Heartbeats ─────────┤ ┌────────────────┘ Cron Jobs ──────────┤ ▼ Hooks ──────────────┘ Claude | Codex | Gemini IPC Watcher ────────── OpenCode | Pi (CLI) │ Markdown Config Files (CLAUDE.md, memory.md, etc.) │ Mission Control Dashboard ◄───────────┘ (http://localhost:3100) JSON Stores (brain, tasks, content) ``` 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 your configured backend CLI (Claude Code, Codex, Gemini, OpenCode, or Pi). The agent can write back to `memory.md` to persist facts across sessions, and send proactive messages via the IPC system. The **Mission Control dashboard** runs on an embedded HTTP server, providing real-time visibility into agent activity, a knowledge store (Second Brain), productivity task tracking, content curation, and full configuration management — all backed by local JSON files with zero external dependencies. Uses your existing subscription or API key for whichever backend you choose — no extra configuration needed. ## Prerequisites - Node.js 18+ - At least one supported coding agent CLI installed and signed in (see [Multi-Backend Support](#multi-backend-support)) - A Discord bot token ([create one here](https://discord.com/developers/applications)) with Message Content Intent enabled ## Quick Start ```bash git clone 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 ``` The dashboard will be available at **http://localhost:3100** once the gateway starts. 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 | | `AGENT_BACKEND` | No | `claude` | Backend runtime: `claude`, `codex`, `gemini`, `opencode`, or `pi` | | `BACKEND_CLI_PATH` | No | *(backend name)* | Path to the backend CLI binary | | `BACKEND_MODEL` | No | — | Model override for the active backend | | `BACKEND_MAX_TURNS` | No | `25` | Max agentic turns per query | | `CLAUDE_CLI_PATH` | No | `claude` | *(Deprecated)* Use `BACKEND_CLI_PATH` instead | | `CONFIG_DIR` | No | `./config` | Path to markdown config directory | | `DASHBOARD_PORT` | No | `3100` | Port for the Mission Control dashboard | | `ALLOWED_TOOLS` | No | `Read,Write,Edit,Glob,Grep,WebSearch,WebFetch` | Comma-separated tools (Claude only) | | `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..." ``` ## Multi-Backend Support Aetheel supports five coding agent CLI backends. Switch between them via the `AGENT_BACKEND` environment variable — no code changes required. | Backend | `AGENT_BACKEND` | CLI | Install | Session Resume | Tool Filtering | |---------|-----------------|-----|---------|----------------|----------------| | **Claude Code** | `claude` *(default)* | `claude` | `npm i -g @anthropic-ai/claude-code` | `--resume ` | ✅ `--allowedTools` | | **Codex** | `codex` | `codex` | `npm i -g @openai/codex` | `exec resume ` | ❌ | | **Gemini CLI** | `gemini` | `gemini` | `npm i -g @anthropic-ai/gemini-cli` | `--resume ` | ❌ | | **OpenCode** | `opencode` | `opencode` | See [OpenCode docs](https://github.com/opencode-ai/opencode) | `--session --continue` | ❌ | | **Pi** | `pi` | `pi` | `npm i -g @mariozechner/pi-coding-agent` | `--session --continue` | ❌ | ### Switching Backends Edit your `.env` file: ```bash # Use Pi as the backend AGENT_BACKEND=pi BACKEND_CLI_PATH=pi # BACKEND_MODEL=anthropic/sonnet # Optional model override ``` ```bash # Use Codex as the backend AGENT_BACKEND=codex BACKEND_CLI_PATH=codex ``` Each backend adapter normalizes the CLI's output into the same internal format (`BackendEventResult`), so all features — sessions, streaming, retries, error handling — work identically regardless of which CLI you use. > **Note:** `ALLOWED_TOOLS` only works with the Claude backend (it's the only CLI that supports `--allowedTools` flags). Other backends will log a warning if `ALLOWED_TOOLS` is configured. ## 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 (each backend uses its own resume mechanism) - 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 Backend 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`). --- ## Mission Control Dashboard An embedded web dashboard for real-time agent monitoring and data management. Accessible at `http://localhost:3100` when the gateway is running. ### Pages | Page | Description | |------|-------------| | **Command Center** | Real-time stats (messages, heartbeats, cron runs, uptime), live activity feed, agent configuration | | **Activity** | Full event history with real-time SSE updates | | **Sessions** | Active Discord channel sessions and message history viewer | | **🧠 Second Brain** | Knowledge store with facts, notes, URLs, and file references — searchable with categories and tags. Also includes memory and persona editors, and a skills viewer | | **📋 Productivity** | Kanban-style task board (To Do → In Progress → Done) with priorities, projects, and due dates | | **📰 Content Intel** | Content curation and tracking — save articles, videos, papers, repos with status workflow (queued → read → archived) | | **⏱️ Scheduler** | View all active cron jobs, heartbeat checks, and lifecycle hooks | | **🔌 Connections** | Status of all integrations (Discord, Claude, heartbeat, cron, IPC, skills) | | **⚙️ Settings** | Agent configuration overview and quick todos | ### Local Storage All dashboard data is persisted as JSON files in the `config/` directory — zero external dependencies: | Store | File | Description | |-------|------|-------------| | Brain facts | `config/brain.json` | Notes, URLs, file references with categories and tags | | Tasks | `config/tasks.json` | Productivity tasks with status, priority, project, due dates | | Content items | `config/content-items.json` | Curated articles, videos, papers with read-status tracking | | Activity log | `config/activity-log.json` | Last 2000 events — survives restarts | | Bot config | `config/bot-config.json` | Dashboard-editable settings | Data is flushed on shutdown and debounced during writes for performance. ### Dashboard Development You can run the dashboard standalone with mock data (no Discord bot or Claude CLI needed): ```bash npm run dashboard ``` This starts a dev server at http://localhost:3100 with simulated activity events and sample data. ### Dashboard API All dashboard APIs are available at the same port: | Endpoint | Method | Description | |----------|--------|-------------| | `/api/stats` | GET | Agent statistics (uptime, messages, heartbeats, cron runs) | | `/api/activity` | GET | Recent activity log entries | | `/api/config` | GET | Agent configuration | | `/api/sessions` | GET | Active sessions | | `/api/messages` | GET | Message history (per channel) | | `/api/cron` | GET | Cron job definitions | | `/api/heartbeats` | GET | Heartbeat definitions | | `/api/hooks` | GET | Lifecycle hook definitions | | `/api/connections` | GET | Integration statuses | | `/api/skills` | GET | Loaded skills | | `/api/memory` | GET/POST | Read/write memory.md | | `/api/persona` | GET/POST | Read/write CLAUDE.md | | `/api/brain` | GET/POST/DELETE | CRUD for brain facts | | `/api/brain?q=...` | GET | Search brain facts | | `/api/tasks` | GET/POST/DELETE | CRUD for productivity tasks | | `/api/tasks/update` | POST | Update task fields (e.g. status) | | `/api/content` | GET/POST/DELETE | CRUD for content items | | `/api/content/update` | POST | Update content fields (e.g. status) | | `/api/bot-config` | GET/POST | Read/write bot configuration | | `/events` | SSE | Real-time event stream | --- ## 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 # Full gateway + dashboard npm run dashboard # Dashboard only (mock data) ``` ## 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, delegates to backend ├── backends/ # Pluggable CLI backend adapters │ ├── types.ts # BackendAdapter interface & BackendName type │ ├── registry.ts # resolveBackendName() & createBackend() factory │ ├── index.ts # Barrel exports │ ├── claude-backend.ts # Claude Code CLI adapter │ ├── codex-backend.ts # OpenAI Codex CLI adapter │ ├── gemini-backend.ts # Google Gemini CLI adapter │ ├── opencode-backend.ts # OpenCode CLI adapter │ └── pi-backend.ts # Pi Coding Agent CLI adapter ├── 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 ├── dashboard-server.ts # Embedded HTTP server for Mission Control ├── dashboard-dev.ts # Standalone dashboard dev server (mock data) ├── activity-log.ts # In-memory + persisted activity event log └── local-store.ts # JSON file persistence layer (brain, tasks, content) dashboard/ # Mission Control frontend ├── index.html # SPA shell with sidebar navigation ├── styles.css # Dark-theme design system (~1700 lines) └── app.js # Client-side SPA (routing, API, rendering) 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) ├── brain.json # Second Brain facts (auto) ├── tasks.json # Productivity tasks (auto) ├── content-items.json # Content Intel items (auto) ├── activity-log.json # Persisted activity log (auto) ├── bot-config.json # Dashboard bot config (auto) ├── messages/ # Message history (auto) ├── conversations/ # Conversation archives (auto) ├── ipc/outbound/ # Proactive message queue (auto) ├── skills/ # Skill definitions └── news/ # Example: agent-created content docs/ ├── PROCESS-FLOW.md # Step-by-step event processing walkthrough └── FUTURE-FEATURES.md # Feature roadmap and ideas ``` ## Development ```bash npm test # Run tests (vitest) npm run dev # Full gateway + embedded dashboard npm run dashboard # Dashboard only with mock data npm run build # Compile TypeScript npm start # Run compiled JS ``` ## License MIT