Add multi-account token rotation, provider fallback, CI monitoring, usage dashboard. Fix Codex description (SDK, not app-server). Add Authentication section with setup-token instructions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.0 KiB
EJClaw
Dual-agent AI assistant (Claude Code + Codex) over Discord.
Originally derived from qwibitai/nanoclaw, now maintained as EJClaw for personal production use.
Overview
Two AI agents running as parallel systemd services on a single host:
- Claude Code (
@claude) — Anthropic Agent SDK, adaptive thinking, Opus/Sonnet - Codex (
@codex) — OpenAI Codex SDK (codex exec), GPT-5.4, xhigh reasoning
Both share the same codebase (dist/index.js), differentiated by environment variables. No containers — direct host processes for zero overhead.
Features
- Dual-agent architecture — Claude Code + Codex as parallel services, shared SQLite (WAL mode)
- Browser automation — gstack browse skill, headless Chromium daemon, ~100ms/command
- Voice transcription — Groq Whisper (primary) / OpenAI Whisper (fallback), shared file cache with dedup
- Bidirectional images — receive Discord attachments as multimodal input, send screenshots back
- Provider fallback — Claude 429 → configurable fallback provider (e.g. Kimi K2.5) with cooldown
- CI monitoring —
watch_ciMCP tool for GitHub Actions run polling (structured fast path, no LLM token cost) - Usage dashboard — real-time token usage and service status overview
- MCP integration — Memento (persistent memory) + EJClaw host tools (send_message, schedule_task, watch_ci, etc.)
- Skill sync — single source of truth, auto-synced to all agent sessions
- Priority queue — per-group serialization, global concurrency limit
- Session persistence — resume conversations across restarts
- Scheduled tasks — cron/interval/once via MCP tool
- Mid-turn steering — inject follow-up messages while agent is working (both agents)
Architecture
Discord ──► SQLite (WAL) ──► GroupQueue ──┬──► Claude Code (Agent SDK, MessageStream)
└──► Codex (Codex SDK, codex exec)
│
IPC polling ◄── follow-up messages (mid-turn steering)
│
Router ──► Discord (text, images, files)
Each agent has access to:
├── MCP tools (send_message, schedule_task, watch_ci, ...)
├── Bash skills (agent-browser → gstack browse, persistent Chromium)
└── Per-group memory (CLAUDE.md / AGENTS.md)
Setup
Prerequisites
- Linux (Ubuntu 22.04+) or macOS
- Node.js 24+ (fnm recommended)
- Claude Code CLI
- Codex CLI (
npm install -g @openai/codex) - Bun 1.0+ (for browser automation)
- Discord bot token
Install
git clone https://github.com/phj1081/EJClaw.git
cd EJClaw
npm install
npm run build:runners
npm run build
Environment
# .env
DISCORD_BOT_TOKEN= # Discord bot token
ASSISTANT_NAME=claude # Bot trigger name (@claude)
CLAUDE_CODE_OAUTH_TOKEN= # Claude Code OAuth token (primary)
CLAUDE_CODE_OAUTH_TOKENS= # Comma-separated tokens for multi-account rotation
OPENAI_API_KEY= # For Codex
GROQ_API_KEY= # Voice transcription (Groq Whisper)
# Provider fallback (optional)
FALLBACK_PROVIDER_NAME= # e.g. kimi
FALLBACK_BASE_URL= # e.g. https://api.kimi.com/coding
FALLBACK_AUTH_TOKEN= # Fallback provider API key
FALLBACK_MODEL= # e.g. kimi-k2.5
Authentication
Multi-account OAuth token rotation is supported via CLAUDE_CODE_OAUTH_TOKENS (comma-separated). When one account hits a rate limit, the system automatically rotates to the next.
Token auto-refresh runs on the Claude service only, refreshing access tokens 30 minutes before expiry using rotating refresh tokens from ~/.claude/.credentials.json (account 0) and ~/.claude-accounts/{n}/.credentials.json (account 1+). Generate tokens with claude setup-token (account 0) or CLAUDE_CONFIG_DIR=~/.claude-accounts/{n} claude setup-token (account 1+).
Systemd Services (Linux)
systemctl --user enable ejclaw ejclaw-codex
systemctl --user start ejclaw ejclaw-codex
# Logs
journalctl --user -u ejclaw -f
journalctl --user -u ejclaw-codex -f
Development
npm run build # Build main project
npm run build:runners # Install + build both runners
npm run dev # Dev mode with hot reload
npm test # Run tests
License
MIT — Originally derived from qwibitai/nanoclaw