chore: update README for MAGI/MoA/Bun + show model names in MoA dashboard
This commit is contained in:
141
README.md
141
README.md
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Dual-agent AI assistant (Claude Code + Codex) over Discord with autonomous paired review.
|
MAGI-style multi-agent AI assistant (Claude Code + Codex + Arbiter) over Discord with autonomous paired review and Mixture of Agents.
|
||||||
|
|
||||||
Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw), now maintained as EJClaw for personal production use.
|
Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw), now maintained as EJClaw for personal production use.
|
||||||
Prompt design inspired by [Q00/ouroboros](https://github.com/Q00/ouroboros), adapted for EJClaw's Discord and dual-service workflow.
|
Prompt design inspired by [Q00/ouroboros](https://github.com/Q00/ouroboros), adapted for EJClaw's Discord and dual-service workflow.
|
||||||
|
Arbiter system inspired by [Evangelion MAGI](https://evangelion.fandom.com/wiki/MAGI) consensus architecture.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -16,44 +17,55 @@ A single unified service (`ejclaw`) manages three Discord bots in one process:
|
|||||||
|
|
||||||
- **Codex-main** (`@codex`) — Owner agent. Handles user requests, writes code.
|
- **Codex-main** (`@codex`) — Owner agent. Handles user requests, writes code.
|
||||||
- **Claude** (`@claude`) — Reviewer agent. Critically reviews owner's work, verifies design direction.
|
- **Claude** (`@claude`) — Reviewer agent. Critically reviews owner's work, verifies design direction.
|
||||||
- **Codex-review** (`@codex-review`) — Fallback reviewer. Takes over when Claude hits rate limits (429).
|
- **Codex-review** (`@codex-review`) — Arbiter agent. Summoned on-demand to break deadlocks between owner and reviewer.
|
||||||
|
|
||||||
Owner and reviewer agent types are configurable via `OWNER_AGENT_TYPE` and `REVIEWER_AGENT_TYPE` in `.env`.
|
All agent types and models are independently configurable per role via `.env`.
|
||||||
|
|
||||||
## Paired Review
|
## MAGI 3-Agent System
|
||||||
|
|
||||||
The core workflow is an autonomous owner-reviewer ping-pong:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
User message
|
User message
|
||||||
→ Owner responds (implementation, answer, etc.)
|
→ Owner responds (implementation, answer, etc.)
|
||||||
→ Reviewer auto-triggered (critical review, design check)
|
→ Reviewer auto-triggered (critical review, design check)
|
||||||
→ Verdict:
|
→ Verdict:
|
||||||
DONE → Owner gets final turn to finalize → Task completed
|
DONE → Owner finalizes → Task completed
|
||||||
DONE_WITH_CONCERNS → Owner addresses feedback → Reviewer re-reviews
|
DONE_WITH_CONCERNS → Owner addresses feedback → loop
|
||||||
BLOCKED → Escalate to user (needs decision)
|
BLOCKED/NEEDS_CONTEXT
|
||||||
NEEDS_CONTEXT → Escalate to user (missing information)
|
├─ Arbiter enabled → Arbiter judges → PROCEED/REVISE/RESET/ESCALATE
|
||||||
|
└─ Arbiter disabled → Escalate to user
|
||||||
|
→ Deadlock (3+ round trips without progress)
|
||||||
|
→ Arbiter summoned → binding verdict → loop resumes
|
||||||
```
|
```
|
||||||
|
|
||||||
The system stops autonomously when the reviewer approves or escalates. No manual intervention needed for the happy path.
|
### Mixture of Agents (MoA)
|
||||||
|
|
||||||
|
When enabled, the arbiter collects opinions from external models (Kimi, GLM, etc.) before rendering its verdict:
|
||||||
|
|
||||||
|
```
|
||||||
|
Deadlock detected → MoA reference queries (Kimi + GLM, parallel)
|
||||||
|
→ Opinions injected into arbiter's prompt
|
||||||
|
→ SDK arbiter (subscription-based) aggregates all perspectives
|
||||||
|
→ Final verdict: PROCEED / REVISE / RESET / ESCALATE
|
||||||
|
```
|
||||||
|
|
||||||
|
No extra SDK processes. External references use lightweight API calls (Anthropic-compatible).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Paired review** — Autonomous owner/reviewer ping-pong with verdict-based control
|
- **MAGI 3-agent system** — Owner/reviewer/arbiter with on-demand deadlock resolution
|
||||||
- **Container-isolated reviewer** — Reviewer runs in persistent Docker container with read-only source mount (kernel-level write protection)
|
- **Mixture of Agents** — External model opinions (Kimi, GLM) enrich arbiter verdicts
|
||||||
- **Post-approval change detection** — Re-triggers review if owner modifies code after reviewer DONE (git tree hash comparison)
|
- **Per-role model selection** — `OWNER_MODEL`, `REVIEWER_MODEL`, `ARBITER_MODEL` + effort + fallback toggle
|
||||||
- **Configurable agent types** — Owner and reviewer roles independently set to `claude-code` or `codex`
|
- **Container-isolated reviewer** — Persistent Docker container with read-only source mount
|
||||||
- **Reviewer fallback** — Claude 429/exhaustion → automatic handoff to codex-review
|
- **Global failover** — Account-level Claude failure → all channels switch to codex, auto-recovers
|
||||||
- **Credential proxy** — API keys never exposed to containers, injected via HTTP proxy
|
- **Post-approval change detection** — Re-triggers review if owner modifies code after approval
|
||||||
- **Voice transcription** — Groq Whisper (primary) / OpenAI Whisper (fallback), shared file cache with dedup
|
- **Voice transcription** — Groq Whisper (primary) / OpenAI Whisper (fallback)
|
||||||
- **Bidirectional images** — Receive Discord attachments as multimodal input, send screenshots back
|
- **Token rotation** — Multi-account Claude/Codex rotation on rate limits
|
||||||
- **Token rotation** — Claude 429 / usage exhaustion → automatic multi-account rotation
|
- **Kimi usage dashboard** — Coding plan 5h/7d usage displayed alongside Claude/Codex
|
||||||
- **MCP integration** — Memento (persistent memory) + EJClaw host tools (send_message, schedule_task, watch_ci, etc.)
|
- **MCP integration** — Memento (persistent memory) + EJClaw host tools
|
||||||
- **Browser automation** — [gstack browse](https://github.com/garrytan/gstack) skill, headless Chromium daemon
|
- **Session persistence** — Separate sessions per role (owner/reviewer/arbiter)
|
||||||
- **Priority queue** — Per-group serialization, global concurrency limit
|
|
||||||
- **Session persistence** — Resume conversations across restarts (separate sessions per role)
|
|
||||||
- **Scheduled tasks** — Cron/interval/once via MCP tool
|
- **Scheduled tasks** — Cron/interval/once via MCP tool
|
||||||
- **Mid-turn steering** — Inject follow-up messages while agent is working
|
- **Mid-turn steering** — Inject follow-up messages while agent is working
|
||||||
|
- **Bun runtime** — Native SQLite (bun:sqlite), fast startup, no native addon builds
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -61,27 +73,26 @@ The system stops autonomously when the reviewer approves or escalates. No manual
|
|||||||
Discord ──► SQLite (WAL) ──► GroupQueue ──┬──► Owner (host process)
|
Discord ──► SQLite (WAL) ──► GroupQueue ──┬──► Owner (host process)
|
||||||
│ │
|
│ │
|
||||||
│ ▼ (auto-trigger)
|
│ ▼ (auto-trigger)
|
||||||
└──► Reviewer (Docker container, :ro mount)
|
├──► Reviewer (Docker container, :ro mount)
|
||||||
│ │
|
│ │
|
||||||
│ Verdict routing
|
│ Verdict routing
|
||||||
│ ├─ DONE → change detection → Owner finalizes or re-review
|
│ ├─ DONE → change detection → finalize or re-review
|
||||||
│ ├─ BLOCKED/NEEDS_CONTEXT → User
|
│ ├─ BLOCKED → Arbiter (if enabled) or User
|
||||||
│ └─ Feedback → Owner (loop)
|
│ └─ Feedback → Owner (loop)
|
||||||
│
|
│
|
||||||
IPC polling ◄── follow-up messages (mid-turn steering)
|
├──► Arbiter (on-demand, fresh session each time)
|
||||||
|
│ │
|
||||||
|
│ ┌───┴─── MoA (if enabled) ───┐
|
||||||
|
│ │ Kimi API ──► opinion │
|
||||||
|
│ │ GLM API ──► opinion │
|
||||||
|
│ │ → injected into prompt │
|
||||||
|
│ └────────────────────────────┘
|
||||||
|
│ │
|
||||||
|
│ PROCEED/REVISE/RESET/ESCALATE
|
||||||
|
│
|
||||||
|
IPC polling ◄── follow-up messages
|
||||||
│
|
│
|
||||||
Router ──► Discord (text, images, files)
|
Router ──► Discord (text, images, files)
|
||||||
|
|
||||||
Owner (host process):
|
|
||||||
├── Stable per-channel worktree (session persists across tasks)
|
|
||||||
├── MCP tools, Bash skills, per-group memory
|
|
||||||
└── Full read-write access
|
|
||||||
|
|
||||||
Reviewer (persistent Docker container):
|
|
||||||
├── Owner workspace mounted read-only (kernel-level protection)
|
|
||||||
├── Credential proxy (API keys never in container)
|
|
||||||
├── pnpm store mounted read-only (if applicable)
|
|
||||||
└── tmpfs for test caches (vitest, jest, npm)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
@@ -89,11 +100,11 @@ Reviewer (persistent Docker container):
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Linux (Ubuntu 22.04+) or macOS
|
- Linux (Ubuntu 22.04+) or macOS
|
||||||
- Node.js 20+ (24 recommended, fnm for version management)
|
- [Bun](https://bun.sh/) 1.3+
|
||||||
- Docker (required for reviewer container isolation)
|
- Docker (required for reviewer container isolation)
|
||||||
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)
|
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)
|
||||||
- [Codex CLI](https://github.com/openai/codex) (`npm install -g @openai/codex`)
|
- [Codex CLI](https://github.com/openai/codex) (`npm install -g @openai/codex`)
|
||||||
- Discord bot tokens (3: Claude, Codex-main, Codex-review)
|
- Discord bot tokens (3: Claude, Codex-main, Codex-review/Arbiter)
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
@@ -113,44 +124,38 @@ All configuration in a single `.env` file:
|
|||||||
# Discord bots (3 tokens for 3 bots)
|
# Discord bots (3 tokens for 3 bots)
|
||||||
DISCORD_BOT_TOKEN= # Claude bot
|
DISCORD_BOT_TOKEN= # Claude bot
|
||||||
DISCORD_CODEX_BOT_TOKEN= # Codex-main bot (owner)
|
DISCORD_CODEX_BOT_TOKEN= # Codex-main bot (owner)
|
||||||
DISCORD_REVIEW_BOT_TOKEN= # Codex-review bot (fallback reviewer)
|
DISCORD_REVIEW_BOT_TOKEN= # Codex-review bot (arbiter)
|
||||||
|
|
||||||
# Agent type configuration
|
# Agent types
|
||||||
OWNER_AGENT_TYPE=codex # codex | claude-code
|
OWNER_AGENT_TYPE=codex # codex | claude-code
|
||||||
REVIEWER_AGENT_TYPE=claude-code # claude-code | codex
|
REVIEWER_AGENT_TYPE=claude-code # claude-code | codex
|
||||||
|
ARBITER_AGENT_TYPE=codex # codex | claude-code (optional, enables 3rd agent)
|
||||||
|
|
||||||
|
# Per-role model overrides
|
||||||
|
OWNER_MODEL=gpt-5.4
|
||||||
|
REVIEWER_MODEL=claude-opus-4-6
|
||||||
|
ARBITER_MODEL=gpt-5.4
|
||||||
|
|
||||||
# API keys
|
# API keys
|
||||||
CLAUDE_CODE_OAUTH_TOKEN= # Claude Code OAuth token
|
CLAUDE_CODE_OAUTH_TOKEN= # Claude Code OAuth token
|
||||||
CLAUDE_CODE_OAUTH_TOKENS= # Comma-separated tokens for multi-account rotation
|
CLAUDE_CODE_OAUTH_TOKENS= # Comma-separated for multi-account rotation
|
||||||
OPENAI_API_KEY= # For Codex
|
|
||||||
GROQ_API_KEY= # Voice transcription (Groq Whisper)
|
GROQ_API_KEY= # Voice transcription (Groq Whisper)
|
||||||
|
|
||||||
# Bot names
|
# Mixture of Agents (MoA)
|
||||||
ASSISTANT_NAME=claude # Claude bot trigger name
|
MOA_ENABLED=true
|
||||||
CODEX_ASSISTANT_NAME=codex # Codex bot trigger name
|
MOA_REF_MODELS=kimi,glm
|
||||||
```
|
MOA_KIMI_MODEL=kimi-k2.5
|
||||||
|
MOA_KIMI_BASE_URL=https://api.kimi.com/coding
|
||||||
### Authentication
|
MOA_KIMI_API_KEY=sk-kimi-xxx
|
||||||
|
MOA_KIMI_API_FORMAT=anthropic
|
||||||
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.
|
MOA_GLM_MODEL=glm-5.1
|
||||||
|
MOA_GLM_BASE_URL=https://open.bigmodel.cn/api/anthropic
|
||||||
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+).
|
MOA_GLM_API_KEY=xxx
|
||||||
|
MOA_GLM_API_FORMAT=anthropic
|
||||||
### Systemd Service (Linux)
|
|
||||||
|
|
||||||
Single unified service:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
systemctl --user restart ejclaw # Restart
|
|
||||||
systemctl --user status ejclaw # Check status
|
|
||||||
systemctl --user enable ejclaw # Enable on boot
|
|
||||||
journalctl --user -u ejclaw -f # Follow logs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deploy
|
### Deploy
|
||||||
|
|
||||||
Build on server, not locally:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh clone-ej@100.64.185.108 'cd ~/EJClaw && git pull && bun run build && bun run build:runners && systemctl --user restart ejclaw'
|
ssh clone-ej@100.64.185.108 'cd ~/EJClaw && git pull && bun run build && bun run build:runners && systemctl --user restart ejclaw'
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -99,9 +99,8 @@ async function queryModel(
|
|||||||
.map((b: { text: string }) => b.text)
|
.map((b: { text: string }) => b.text)
|
||||||
.join('');
|
.join('');
|
||||||
} else {
|
} else {
|
||||||
content = (
|
content = (data as { choices?: { message?: { content?: string } }[] })
|
||||||
data as { choices?: { message?: { content?: string } }[] }
|
.choices?.[0]?.message?.content;
|
||||||
).choices?.[0]?.message?.content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content) throw new Error('Empty response from model');
|
if (!content) throw new Error('Empty response from model');
|
||||||
|
|||||||
@@ -595,7 +595,9 @@ function buildModelConfigSection(): string {
|
|||||||
// MoA status
|
// MoA status
|
||||||
const moaConfig = getMoaConfig();
|
const moaConfig = getMoaConfig();
|
||||||
if (moaConfig.enabled) {
|
if (moaConfig.enabled) {
|
||||||
const refs = moaConfig.referenceModels.map((m) => m.name).join(', ');
|
const refs = moaConfig.referenceModels
|
||||||
|
.map((m) => `${m.name} \`${m.model}\``)
|
||||||
|
.join(', ');
|
||||||
lines.push(` **MoA** — ${refs}`);
|
lines.push(` **MoA** — ${refs}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user