From 0185b5e6b6f90f6b640e8575deeb11eb217e3f8d Mon Sep 17 00:00:00 2001 From: ejclaw Date: Sat, 11 Apr 2026 21:00:10 +0900 Subject: [PATCH] docs: prepare 0.2.0 release notes --- CHANGELOG.md | 39 +++++- README.md | 278 ++++++++++++++++++------------------------ docs/architecture.md | 169 +++++++++++++------------ docs/configuration.md | 154 ++++++++++++++++------- package.json | 4 +- 5 files changed, 354 insertions(+), 290 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 974a034..383986a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,39 @@ # Changelog -All notable changes to EJClaw will be documented in this file. +이 문서는 EJClaw의 주요 변경 사항을 기록합니다. -## [1.2.0](https://github.com/phj1081/EJClaw/compare/v1.1.6...v1.2.0) +## [0.2.0] - 2026-04-11 -[BREAKING] WhatsApp removed from core, now a skill. Run `/add-whatsapp` to re-add (existing auth/groups preserved). -- **fix:** Prevent scheduled tasks from executing twice when container runtime exceeds poll interval (#138, #669) +### Added + +- owner / reviewer / arbiter 기반 Tribunal 3-에이전트 흐름 정비 +- MoA(Mixture of Agents) 기반 외부 모델 의견 수집 +- `assign_room` 기반 room assignment 모델과 `room_settings` SSOT 정착 +- 역할별 model / effort / fallback 설정 +- reviewer host runtime read-only guard 및 host verification 경로 +- Claude OAuth 멀티 토큰 로테이션 + +### Changed + +- reviewer는 owner workspace를 direct mount로 읽는 현재 모델로 정리 +- final delivery 경로를 단일화해 duplicate final 배달 문제를 줄임 +- startup precondition을 전용 오류 / exit code 체계로 정리해 crash loop를 막음 +- deploy 과정에 `migrate-room-registrations`를 포함해 startup strictness와 운영 절차를 맞춤 +- Bun 기준 단일 quality gate(`bun run check`)로 format / typecheck / test / build를 통합 + +### Fixed + +- stale paired finalize retry가 이전 attempt의 side effect를 밖으로 새는 문제 수정 +- reviewer / arbiter intermediate progress가 final 직전에 외부 채팅으로 flush되는 문제 수정 +- owner final이 progress edit + 새 work item 메시지로 이중 배달되는 문제 수정 +- owner workspace branch mismatch 시 안전한 auto-repair 또는 visible blocked 처리 추가 +- stale reviewer workspace 레코드가 옛 경로를 유지해 reviewer가 다른 worktree를 보는 문제 수정 +- legacy room migration 미실행 상태에서 서비스가 restart loop에 빠지는 문제 완화 + +## [0.1.0] - 2026-04-09 + +### Added + +- Discord 기반 EJClaw 초기 공개 버전 +- owner / reviewer / arbiter 역할 고정 봇 구조 +- auto user notify, loop protection, Discord-independent paired communication 기반 정착 diff --git a/README.md b/README.md index 0c54364..57b0a20 100644 --- a/README.md +++ b/README.md @@ -1,220 +1,180 @@ # EJClaw -![Version](https://img.shields.io/badge/version-0.1.0-blue) +![Version](https://img.shields.io/badge/version-0.2.0-blue) ![Claude Agent SDK](https://img.shields.io/badge/Claude_Agent_SDK-0.2.87-blueviolet) ![Codex SDK](https://img.shields.io/badge/Codex_SDK-0.117.0-green) ![Bun](https://img.shields.io/badge/Bun-1.3+-f9f1e1?logo=bun&logoColor=black) -![Discord](https://img.shields.io/badge/Discord-Bot-5865F2?logo=discord&logoColor=white) +![Discord](https://img.shields.io/badge/Discord-Tribunal-5865F2?logo=discord&logoColor=white) -Tribunal multi-agent AI assistant (Owner + Reviewer + Arbiter) over Discord with autonomous paired review and Mixture of Agents. +EJClaw는 Discord 위에서 동작하는 Tribunal 멀티에이전트 개발 보조 시스템입니다. +사용자 요청은 owner가 받고, reviewer가 자동 리뷰를 수행하며, 필요할 때 arbiter가 교착을 정리합니다. -Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw), now independently maintained as EJClaw. -Prompt design inspired by [Q00/ouroboros](https://github.com/Q00/ouroboros) and [garrytan/gstack](https://github.com/garrytan/gstack), adapted for EJClaw's Discord and dual-service workflow. -Tribunal arbiter system inspired by multi-agent consensus architectures. +원본은 [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw)에서 출발했지만, 현재는 EJClaw의 Discord/paired-runtime 구조에 맞게 독립적으로 유지되고 있습니다. -## Overview +## 개요 -A single unified service (`ejclaw`) runs a **Tribunal** of three roles while -managing three Discord bots in one process: +- 단일 `ejclaw` 서비스가 owner / reviewer / arbiter 세 역할과 세 Discord 봇을 함께 관리합니다. +- 사용자 진입점은 owner 하나이며, reviewer와 arbiter는 내부 역할로 동작합니다. +- room-level 설정은 `room_settings`를 기준으로 하며, `assign_room`이 공개 assignment 인터페이스입니다. +- reviewer는 owner의 현재 worktree를 direct mount로 읽고, role-scoped read-only 보호를 적용받습니다. +- paired runtime은 SQLite(WAL), stable owner worktree, turn/lease 추적, host verification으로 구성됩니다. -| Role | Purpose | -|------|---------| -| **Owner** | Handles user requests, writes code | -| **Reviewer** | Critically reviews owner's work, verifies design direction | -| **Arbiter** | On-demand deadlock breaker between owner and reviewer | +## 핵심 기능 -The identity layer is role-fixed: +- Tribunal 3-에이전트 루프: owner / reviewer / arbiter +- Mixture of Agents(MoA): 외부 모델 의견을 arbiter 판단에 주입 +- 역할별 agent type / model / effort 설정 +- role-fixed Discord 봇 3개 체계 +- reviewer host runtime + read-only guard +- 승인 후 변경 감지와 재리뷰 +- Claude 장애 시 Codex로 넘기는 global failover +- Claude OAuth 멀티 토큰 로테이션 +- `assign_room` 기반 명시적 room assignment +- Bun + SQLite 기반 빠른 런타임 -- **Owner bot** — Handles the owner turn output slot. -- **Reviewer bot** — Handles the reviewer turn output slot. -- **Arbiter bot** — Handles the arbiter turn output slot. +## Tribunal 시스템 -Each role's agent type and model are independently configurable via `.env` -(`OWNER_AGENT_TYPE`, `REVIEWER_AGENT_TYPE`, `ARBITER_AGENT_TYPE`, `*_MODEL`). -Three Discord bots provide the identity layer — which bot speaks is determined -by the active role, not hardcoded. +| 역할 | 현재 기본값 | 설명 | +| --- | --- | --- | +| Owner | room별 `owner_agent_type` (기본 Codex) | 사용자 요청 처리, 코드 작성, 최종 응답 | +| Reviewer | 전역 `REVIEWER_AGENT_TYPE` (기본 Claude Code) | owner 결과 비판적 리뷰, 회귀 검증 | +| Arbiter | 전역 `ARBITER_AGENT_TYPE` (옵션) | owner/reviewer 교착 시 판정 | -## Room Assignment Model - -Per-room routing now uses an explicit assignment model: - -- `room_settings` is the room-level source of truth (SSOT) -- Each room stores: - - `room_mode`: `single` or `tribunal` - - `owner_agent_type`: `codex` or `claude-code` -- Public room assignment uses `assign_room` -- Legacy `register_group` public interfaces were removed -- `registered_groups` remains as a materialized capability/read-model layer and legacy fallback, not the authoritative room configuration - -Operationally: - -- `single` → one owner bot -- `tribunal` → per-room owner + globally configured reviewer + optional arbiter - -This means tribunal is no longer inferred from “two bots registered on one room”; it is an explicit room setting. - -## Tribunal Flow - -``` -User message - → Owner responds (implementation, answer, etc.) - → Reviewer auto-triggered (critical review, design check) - → Verdict: - DONE → Owner finalizes → Task completed → @user ✅ - DONE_WITH_CONCERNS → Owner addresses feedback → loop +```text +사용자 메시지 + → Owner 응답 + → Reviewer 자동 실행 + → verdict: + DONE → Owner finalize → 완료 + DONE_WITH_CONCERNS → Owner 수정 → 재리뷰 루프 BLOCKED/NEEDS_CONTEXT - ├─ Arbiter enabled → Arbiter judges → PROCEED/REVISE/RESET/ESCALATE - └─ Arbiter disabled → Escalate to user → @user ⚠️ - → Owner BLOCKED/NEEDS_CONTEXT → Arbiter (same path as reviewer) - → Deadlock (2+ round trips without progress) - → Arbiter summoned → binding verdict → loop resumes + ├─ Arbiter enabled → Arbiter 판정 + └─ Arbiter disabled → 사용자로 에스컬레이션 + → 왕복이 누적되면 arbiter 자동 요청 가능 ``` -### Mixture of Agents (MoA) +### MoA -When enabled, the arbiter collects opinions from external models (Kimi, GLM, etc.) before rendering its verdict: +MoA가 켜져 있으면 arbiter가 판정하기 전에 Kimi, GLM 같은 외부 모델 의견을 병렬 수집하고, 그 결과를 arbiter 프롬프트에 주입합니다. 최종 판정은 여전히 EJClaw arbiter가 내립니다. -``` -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). +현재 room 설정의 기준은 다음과 같습니다. -## Features +- `room_settings`: room-level SSOT +- `room_role_overrides`: owner / reviewer / arbiter 역할별 override +- `paired_projects`: canonical project root +- `paired_workspaces`: 실제 owner / reviewer 실행 workspace +- `registered_groups`: 완전히 제거되지는 않았지만, canonical source가 아니라 compatibility/read-model 성격으로 남아 있는 레이어 -- **Tribunal 3-agent system** — Owner/reviewer/arbiter with on-demand deadlock resolution -- **Discord-independent communication** — Agent-to-agent data flows directly via DB, Discord is display-only -- **Mixture of Agents** — External model opinions (Kimi, GLM) enrich arbiter verdicts -- **Per-role model selection** — `OWNER_MODEL`, `REVIEWER_MODEL`, `ARBITER_MODEL` + effort + fallback toggle -- **Host reviewer with read-only guards** — Reviewer runs on host with role-scoped sandbox and guard policy -- **Global failover** — Account-level Claude failure → all channels switch to codex, auto-recovers -- **Post-approval change detection** — Re-triggers review if owner modifies code after approval -- **Auto user notification** — @mention on task completion (✅ done, ⚠️ escalated) -- **Loop protection** — Deadlock threshold, merge_ready oscillation guard, arbiter re-invocation limit -- **Voice transcription** — Groq Whisper (primary) / OpenAI Whisper (fallback) -- **Token rotation** — Multi-account Claude/Codex rotation on rate limits -- **Kimi usage dashboard** — Coding plan 5h/7d usage displayed alongside Claude/Codex -- **MCP integration** — Memento (persistent memory) + EJClaw host tools -- **Session persistence** — Separate sessions per role (owner/reviewer/arbiter) -- **Scheduled tasks** — Cron/interval/once via MCP tool -- **Mid-turn steering** — Inject follow-up messages while agent is working -- **Bun runtime** — Native SQLite (bun:sqlite), fast startup, no native addon builds +운영적으로는: -## Architecture +- `single` → owner만 실행 +- `tribunal` → owner + reviewer + optional arbiter -``` +중요한 점: + +- reviewer는 더 이상 snapshot copy를 기본 실행 경로로 쓰지 않습니다. +- reviewer는 owner의 현재 workspace를 direct mount로 읽습니다. +- stale reviewer workspace 레코드가 남아 있어도 실행 직전 owner 현재 경로로 재동기화됩니다. + +## 아키텍처 + +```text Discord ──► SQLite (WAL) ──► GroupQueue ──┬──► Owner (host process) │ │ - │ ▼ (auto-trigger) - ├──► Reviewer (host process, read-only guarded) + │ ▼ + ├──► Reviewer (host process, read-only) │ │ - │ Verdict routing - │ ├─ DONE → change detection → finalize or re-review - │ ├─ BLOCKED → Arbiter (if enabled) or User - │ └─ Feedback → Owner (loop) + │ verdict routing + │ ├─ DONE → finalize + │ ├─ feedback → owner loop + │ └─ BLOCKED → arbiter / user │ - ├──► Arbiter (on-demand, fresh session each time) + ├──► Arbiter (on-demand, fresh session) │ │ - │ ┌───┴─── MoA (if enabled) ───┐ - │ │ Kimi API ──► opinion │ - │ │ GLM API ──► opinion │ - │ │ → injected into prompt │ - │ └────────────────────────────┘ - │ │ - │ PROCEED/REVISE/RESET/ESCALATE + │ ┌───┴─── MoA ───┐ + │ │ Kimi / GLM │ + │ │ 의견 수집 │ + │ └───────────────┘ │ - IPC polling ◄── follow-up messages + IPC follow-up / host tools │ ┌────────── Router ──────────┐ ▼ ▼ - paired_turn_outputs Discord (display only) - (agent ↔ agent data) (user observation, @mention) + paired_turn_outputs Discord display ``` -## Setup +## 시작하기 -### Prerequisites +### 요구사항 -- Linux (Ubuntu 22.04+) or macOS +- Linux(Ubuntu 22.04+) 또는 macOS - [Bun](https://bun.sh/) 1.3+ -- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) -- [Codex CLI](https://github.com/openai/codex) (`npm install -g @openai/codex`) -- Discord bot tokens (3: owner, reviewer, arbiter) +- Claude Code CLI +- Codex CLI +- Discord 봇 토큰 3개(owner / reviewer / arbiter) -### Install +### 설치 ```bash git clone https://github.com/phj1081/EJClaw.git cd EJClaw bun install -bun run build:runners -bun run build +bun run build:all ``` -## Documentation +### 환경 설정 -- [Architecture](docs/architecture.md) — Data flow, room model, verification execution, key files -- [Configuration](docs/configuration.md) — Full `.env` reference, debugging paths - -### Environment - -All configuration in a single `.env` file: +- `.env.example`를 기준으로 `.env`를 작성합니다. +- 전체 키 설명은 [docs/configuration.md](docs/configuration.md)를 봅니다. +- 최소한 아래는 먼저 채워야 합니다. ```bash -# Discord bots (canonical role-fixed names) -DISCORD_OWNER_BOT_TOKEN= # Owner bot -DISCORD_REVIEWER_BOT_TOKEN= # Reviewer bot -DISCORD_ARBITER_BOT_TOKEN= # Arbiter bot - -# Old service-based token names are no longer accepted. -# Rename existing values to the canonical role-based keys above. - -# Agent types -OWNER_AGENT_TYPE=codex # codex | claude-code -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 -CLAUDE_CODE_OAUTH_TOKEN= # Claude Code OAuth token -CLAUDE_CODE_OAUTH_TOKENS= # Comma-separated for multi-account rotation -GROQ_API_KEY= # Voice transcription (Groq Whisper) - -# Mixture of Agents (MoA) -MOA_ENABLED=true -MOA_REF_MODELS=kimi,glm -MOA_KIMI_MODEL=kimi-k2.5 -MOA_KIMI_BASE_URL=https://api.kimi.com/coding -MOA_KIMI_API_KEY=sk-kimi-xxx -MOA_KIMI_API_FORMAT=anthropic -MOA_GLM_MODEL=glm-5.1 -MOA_GLM_BASE_URL=https://open.bigmodel.cn/api/anthropic -MOA_GLM_API_KEY=xxx -MOA_GLM_API_FORMAT=anthropic +DISCORD_OWNER_BOT_TOKEN= +DISCORD_REVIEWER_BOT_TOKEN= +DISCORD_ARBITER_BOT_TOKEN= +CLAUDE_CODE_OAUTH_TOKENS= +OWNER_AGENT_TYPE=codex +REVIEWER_AGENT_TYPE=claude-code ``` -### Deploy +### 실행 + +```bash +bun run dev +``` + +### 배포 ```bash bun run deploy ``` -## Development +이 스크립트는 다음을 순서대로 수행합니다. + +1. 최신 커밋 fast-forward pull +2. 전체 build +3. `migrate-room-registrations` 실행 +4. `systemctl --user restart ejclaw` + +## 개발 ```bash -bun run build # Build main project -bun run build:runners # Install + build both runners -bun run dev # Dev mode with hot reload -bun test # Run tests +bun run build +bun run build:runners +bun run test +bun run typecheck +bun run check ``` -## License +## 문서 -MIT — Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw) +- [docs/architecture.md](docs/architecture.md) — 데이터 모델, 실행 흐름, 주요 파일 +- [docs/configuration.md](docs/configuration.md) — `.env` 키와 디버깅 경로 +- [docs/legacy-compat-removal-spec.md](docs/legacy-compat-removal-spec.md) — 남아 있는 레거시 제거 계획 +- [CHANGELOG.md](CHANGELOG.md) — 릴리즈 이력 + +## 라이선스 + +MIT diff --git a/docs/architecture.md b/docs/architecture.md index 807b7d6..e8917bf 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,107 +1,118 @@ -# Architecture +# 아키텍처 -## Service Stack +## 서비스 구성 -Single unified service (`ejclaw`) manages all three Discord bots in one process: +EJClaw는 단일 `ejclaw` 서비스가 세 Discord 봇과 paired runtime을 함께 운영하는 구조입니다. -- `ejclaw.service` — Single unified process -- Discord bots: `DISCORD_OWNER_BOT_TOKEN` (owner), `DISCORD_REVIEWER_BOT_TOKEN` (reviewer), `DISCORD_ARBITER_BOT_TOKEN` (arbiter) -- Paired review: owner ↔ reviewer (agent types configurable per role) -- Reviewer fallback: Claude exhaustion → codex-review auto-handoff -- Shared dirs: `store/`, `groups/`, `data/` -- SQLite WAL mode + `busy_timeout=5000` for concurrent access +- `ejclaw.service`: 단일 unified process +- Discord 봇: + - `DISCORD_OWNER_BOT_TOKEN` + - `DISCORD_REVIEWER_BOT_TOKEN` + - `DISCORD_ARBITER_BOT_TOKEN` +- 저장소: + - `store/`: SQLite DB + - `groups/`: room별 로그 / 메모리 / 설정 + - `data/`: 세션, worktree, 런타임 보조 데이터 +- SQLite는 WAL + `busy_timeout=5000` 기준으로 동작 -## Data Flow +## 핵심 데이터 모델 -``` +| 구성 요소 | 역할 | +| --- | --- | +| `room_settings` | room-level SSOT | +| `room_role_overrides` | 역할별 agent type / agentConfig override | +| `paired_projects` | canonical project root (`canonical_work_dir`) | +| `paired_tasks` | paired runtime의 상태 머신 | +| `paired_workspaces` | owner / reviewer의 실제 실행 workspace 경로 | +| `registered_groups` | compatibility / materialized read-model 성격의 잔존 레이어 | + +현재 기준에서 중요한 점: + +- room 설정의 기준은 `room_settings` +- reviewer / arbiter는 room의 공개 진입점이 아니라 내부 역할 +- `registered_groups`는 제거 진행 대상이지만 아직 완전히 사라진 것은 아님 + +## 실행 흐름 + +```text Discord ──► SQLite (WAL) ──► GroupQueue ──┬──► Owner (host process) │ │ - │ ▼ (auto-trigger) - ├──► Reviewer (host process, read-only guarded) + │ ▼ + ├──► Reviewer (host process, read-only) │ │ - │ Verdict routing - │ ├─ DONE → change detection → finalize or re-review - │ ├─ BLOCKED → Arbiter (if enabled) or User - │ └─ Feedback → Owner (loop) + │ verdict routing + │ ├─ DONE → owner finalize + │ ├─ feedback → owner loop + │ └─ BLOCKED → arbiter / user │ - ├──► Arbiter (on-demand, fresh session each time) + ├──► Arbiter (on-demand) │ │ - │ ┌───┴─── MoA (if enabled) ───┐ - │ │ Ref model A ──► opinion │ - │ │ Ref model B ──► opinion │ - │ │ → injected into prompt │ - │ └────────────────────────────┘ - │ │ - │ PROCEED/REVISE/RESET/ESCALATE + │ ┌───┴─── MoA ───┐ + │ │ Kimi / GLM │ + │ │ 의견 수집 │ + │ └───────────────┘ │ - IPC polling ◄── follow-up messages + IPC polling / host tools │ ┌────────── Router ──────────┐ ▼ ▼ - paired_turn_outputs Discord (display only) - (agent ↔ agent data) (user observation, @mention) + paired_turn_outputs Discord display ``` -## Room Assignment Model +## Tribunal 역할 분리 -Per-room routing uses an explicit assignment model: +| 역할 | 기본 선택 | 설명 | +| --- | --- | --- | +| owner | room별 `owner_agent_type` (기본 Codex) | 사용자 요청 처리, 코드 작성, 최종 응답 | +| reviewer | 전역 `REVIEWER_AGENT_TYPE` (기본 Claude Code) | owner 결과 검토, 회귀 검증 | +| arbiter | 전역 `ARBITER_AGENT_TYPE` (옵션) | owner / reviewer 교착 시 판정 | -- `room_settings` is the room-level source of truth (SSOT) -- Each room stores: - - `room_mode`: `single` or `tribunal` - - `owner_agent_type`: `codex` or `claude-code` -- Public room assignment uses `assign_room` -- `registered_groups` is a legacy projection being removed from setup/verify/runtime read paths -- Refactor target and migration sequence live in `docs/legacy-compat-removal-spec.md` +역할별 model / effort는 전역 env(`OWNER_*`, `REVIEWER_*`, `ARBITER_*`)로 정하고, room-level `agentConfig`는 provider별(`claudeModel`, `codexModel`) override만 제공합니다. -Operationally: +## Reviewer / Arbiter runtime -- `single` → one owner bot -- `tribunal` → per-room owner + globally configured reviewer + optional arbiter +- reviewer는 owner의 현재 workspace를 direct mount로 읽습니다 +- snapshot copy는 현재 기본 실행 경로가 아닙니다 +- reviewer workspace 레코드가 오래된 경로를 가리키면 실행 직전에 owner 현재 workspace로 재동기화합니다 +- arbiter는 reviewer와 같은 read-only workspace를 쓰되, 세션 디렉토리는 매 호출마다 fresh하게 준비합니다 -Tribunal is no longer inferred from "two bots registered on one room"; it is an explicit room setting. +즉 reviewer가 보는 실행 경로는: -## Tribunal 3-Agent System +1. `paired_projects.canonical_work_dir` 같은 canonical root와 별개로 +2. `paired_workspaces.workspace_dir`에 저장된 실제 owner worktree -``` -User message - → Owner responds (implementation, answer, etc.) - → Reviewer auto-triggered (critical review, design check) - → Verdict: - DONE → Owner finalizes → Task completed → @user ✅ - DONE_WITH_CONCERNS → Owner addresses feedback → loop - BLOCKED/NEEDS_CONTEXT - ├─ Arbiter enabled → Arbiter judges → PROCEED/REVISE/RESET/ESCALATE - └─ Arbiter disabled → Escalate to user → @user ⚠️ - → Owner BLOCKED/NEEDS_CONTEXT → Arbiter (same path as reviewer) - → Deadlock (2+ round trips without progress) - → Arbiter summoned → binding verdict → loop resumes -``` +입니다. -## Verification Execution +## 세션 / 프롬프트 구성 -Reviewer and arbiter now run as host processes with role-scoped read-only -guards and sandbox settings. Verification profiles run directly on the host with -restricted environment variables and snapshot checks: +- owner는 stable worktree + stable session을 사용 +- reviewer / arbiter는 read-only 세션 디렉토리를 매 실행 전에 다시 준비 +- `prepareReadonlySessionEnvironment()`가 `CLAUDE.md`, `.codex/AGENTS.md`, 설정 파일을 매번 재생성 +- 그래서 reviewer 관련 프롬프트 / workspace 변경은 기존 실행 중 프로세스에는 즉시 적용되지 않지만, **다음 reviewer 턴부터는 자동 반영**됩니다 -- Fixed-profile direct execution (`test`, `typecheck`, `build`) -- Snapshot comparison before/after execution -- Root-level runtime/build directories excluded from verification snapshot -- Role-scoped reviewer safeguards remain independent of verification execution +## 검증 / 운영 경로 -## Key Files +- 검증 명령은 `bun run check` 하나로 묶여 있음 + - format + - typecheck + - test + - build +- reviewer / arbiter가 직접 로컬 빌드를 못 돌려도, host verification 경로로 `typecheck`, `test`, `build`를 수행할 수 있음 +- startup precondition은 전용 오류로 올리고, `RestartPreventExitStatus=78`로 crash loop를 막음 +- deploy는 `migrate-room-registrations`를 선행한 뒤 service restart를 수행 -| File | Purpose | -| ------------------------- | ---------------------------------------------------------- | -| `src/index.ts` | Orchestrator: state, message loop, agent invocation | -| `src/agent-runner.ts` | Spawns agent processes, manages env/sessions/skills | -| `src/verification.ts` | Fixed-profile verification execution with snapshot checks | -| `src/channels/discord.ts` | Discord channel (8s typing refresh, Whisper transcription) | -| `src/ipc.ts` | IPC watcher and task processing | -| `src/router.ts` | Message formatting and outbound routing | -| `src/config.ts` | Trigger pattern, paths, intervals | -| `src/task-scheduler.ts` | Runs scheduled tasks | -| `src/db.ts` | SQLite operations | -| `runners/agent-runner/` | Claude Code runner (Agent SDK) | -| `runners/codex-runner/` | Codex runner (SDK, `codex exec` wrapper) | -| `groups/{name}/CLAUDE.md` | Per-group memory (isolated) | +## 주요 파일 + +| 파일 | 역할 | +| --- | --- | +| `src/index.ts` | 전체 오케스트레이션 진입점 | +| `src/message-runtime.ts` | 메시지 루프, paired flow 연결 | +| `src/message-turn-controller.ts` | progress / final delivery 제어 | +| `src/paired-execution-context.ts` | owner / reviewer / arbiter 실행 준비 | +| `src/paired-workspace-manager.ts` | owner / reviewer workspace 관리 | +| `src/agent-runner.ts` | host process spawn, env/session wiring | +| `src/db.ts` | 런타임 DB facade | +| `src/db/` | canonical room / paired state / migration 로직 | +| `runners/agent-runner/` | Claude Code runner | +| `runners/codex-runner/` | Codex runner | +| `setup/` | setup / verify / service rendering | diff --git a/docs/configuration.md b/docs/configuration.md index 36c3ffe..e4c6ae4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,83 +1,145 @@ -# Configuration +# 설정 -All configuration in a single `.env` file. +EJClaw의 설정 기준은 `.env` 하나입니다. +프로젝트 루트의 [`../.env.example`](../.env.example)를 기본 예시로 보고, 이 문서는 현재 런타임에서 의미가 있는 키만 추려 설명합니다. -## Discord Bots +## 기본 원칙 + +- Discord 토큰은 role-fixed canonical 키만 사용합니다 +- reviewer 기본 provider는 `claude-code` +- owner 기본 provider는 `codex` +- room-level override는 provider 단위(`claudeModel`, `codexModel`)만 지원합니다 +- `CLAUDE_CODE_OAUTH_TOKENS`가 canonical이고, `CLAUDE_CODE_OAUTH_TOKEN`은 legacy fallback입니다 + +## Discord 봇 ```bash -DISCORD_OWNER_BOT_TOKEN= # Owner bot -DISCORD_REVIEWER_BOT_TOKEN= # Reviewer bot -DISCORD_ARBITER_BOT_TOKEN= # Arbiter bot +DISCORD_OWNER_BOT_TOKEN= +DISCORD_REVIEWER_BOT_TOKEN= +DISCORD_ARBITER_BOT_TOKEN= ``` -## Agent Types & Models +예전 service-based alias는 더 이상 허용되지 않습니다. + +## 역할 / 모델 설정 ```bash -# Agent types per role -OWNER_AGENT_TYPE=codex # codex | claude-code -REVIEWER_AGENT_TYPE=claude-code # claude-code | codex -ARBITER_AGENT_TYPE=codex # codex | claude-code (optional, enables 3rd agent) +# 역할별 provider +OWNER_AGENT_TYPE=codex +REVIEWER_AGENT_TYPE=claude-code +# ARBITER_AGENT_TYPE=claude-code -# Per-role model overrides +# provider 기본 모델 +CLAUDE_MODEL=claude-opus-4-6 +CLAUDE_EFFORT=high +CLAUDE_THINKING=adaptive +CODEX_MODEL=gpt-5.4 +CODEX_EFFORT=xhigh + +# 역할별 override OWNER_MODEL=gpt-5.4 -REVIEWER_MODEL=claude-opus-4-6 -ARBITER_MODEL=gpt-5.4 - -# Per-role effort level OWNER_EFFORT=xhigh +OWNER_FALLBACK_ENABLED=true + +REVIEWER_MODEL=claude-opus-4-6 REVIEWER_EFFORT=high -ARBITER_EFFORT=xhigh +REVIEWER_FALLBACK_ENABLED=true -# Per-role fallback toggle -REVIEWER_FALLBACK_ENABLED=true # Auto-handoff to codex when Claude exhausted -ARBITER_FALLBACK_ENABLED=false - -# Response language -AGENT_LANGUAGE=Korean # Injected into all agent prompts +ARBITER_MODEL=claude-sonnet-4-6 +ARBITER_EFFORT=high +ARBITER_FALLBACK_ENABLED=true ``` -## Authentication +설명: + +- reviewer / arbiter provider 선택은 **전역 설정** +- 특정 방에서만 reviewer를 Codex로 고르는 기능은 없음 +- room-level `agentConfig`의 `claudeModel`, `codexModel`은 역할별이 아니라 provider별 override +- `ARBITER_AGENT_TYPE`은 옵션이며, 설정하지 않으면 arbiter는 비활성 상태입니다 + +## 인증 ```bash -CLAUDE_CODE_OAUTH_TOKEN= # Claude Code OAuth token -CLAUDE_CODE_OAUTH_TOKENS= # Comma-separated for multi-account rotation -OPENAI_API_KEY= # Codex API key (if not using OAuth) +# Claude Code OAuth +CLAUDE_CODE_OAUTH_TOKENS= +CLAUDE_CODE_OAUTH_TOKEN= + +# Claude host env (선택) +ANTHROPIC_API_KEY= +ANTHROPIC_AUTH_TOKEN= +ANTHROPIC_BASE_URL= ``` -## Voice Transcription +설명: + +- `CLAUDE_CODE_OAUTH_TOKENS`: canonical, 쉼표 구분 +- `CLAUDE_CODE_OAUTH_TOKEN`: 단일 토큰 legacy fallback +- 실제 runner에는 현재 선택된 Claude 토큰 하나만 주입됩니다 + +Codex 쪽은 현재 **OAuth 세션 파일** 기준으로 동작합니다. `OPENAI_API_KEY`를 Codex child process에 넘겨서 빌링하는 구조는 사용하지 않습니다. + +## 음성 전사 ```bash -GROQ_API_KEY= # Groq whisper-large-v3-turbo (primary) -OPENAI_API_KEY= # OpenAI whisper-1 (fallback) +GROQ_API_KEY= ``` -## Mixture of Agents (MoA) +- 기본은 Groq Whisper +- 필요 시 OpenAI Whisper fallback을 별도 확장할 수 있지만, 현재 README / 문서 기준 최소 키는 `GROQ_API_KEY`입니다 + +## MoA ```bash MOA_ENABLED=true -MOA_REF_MODELS=kimi,glm # Configurable reference model list +MOA_REF_MODELS=kimi,glm -# Per-model config (pattern: MOA_{NAME}_{SETTING}) MOA_KIMI_MODEL=kimi-k2.5 MOA_KIMI_BASE_URL=https://api.kimi.com/coding MOA_KIMI_API_KEY=sk-kimi-xxx MOA_KIMI_API_FORMAT=anthropic -MOA_GLM_MODEL=glm-5.1 -MOA_GLM_BASE_URL=https://open.bigmodel.cn/api/anthropic +MOA_GLM_MODEL=glm-4-plus +MOA_GLM_BASE_URL=https://open.bigmodel.cn/api/paas/v4 MOA_GLM_API_KEY=xxx MOA_GLM_API_FORMAT=anthropic ``` -## Debugging Paths +MoA는 arbiter 판정 전에 외부 모델 의견을 수집해 prompt에 주입합니다. +`API_FORMAT` 같은 항목은 `.env.example`의 최소 예시에 없는 운영 확장 키입니다. -| Item | Path | -|------|------| -| **DB** | `store/messages.db` (shared, WAL mode) | -| Service log | `journalctl --user -u ejclaw -f` or `logs/ejclaw.log` | -| Per-group logs | `groups/{name}/logs/` | -| Claude sessions | `data/sessions/{name}/.claude/` | -| Codex sessions | `data/sessions/{name}/.codex/` | -| Claude platform rules | `prompts/claude-platform.md` | -| Codex platform rules | `prompts/codex-platform.md` | -| Global memory | `groups/global/CLAUDE.md` | +## 운영 / 배포 관련 설정 + +```bash +ASSISTANT_NAME=claude +STATUS_CHANNEL_ID= +SESSION_COMMAND_ALLOWED_SENDERS= +MAX_CONCURRENT_AGENTS=5 +``` + +- `ASSISTANT_NAME`은 owner trigger 기본 이름을 만듭니다 +- paired room에서도 사용자 진입점은 owner가 기준입니다 +- status dashboard와 session command는 선택 설정입니다 + +## 디버깅 경로 + +| 항목 | 경로 / 명령 | +| --- | --- | +| DB | `store/messages.db` | +| 서비스 로그 | `journalctl --user -u ejclaw -f` | +| room 로그 | `groups/{folder}/logs/` | +| owner/reviewer 세션 | `data/sessions/{folder}*` | +| owner worktree | `data/workspaces/{folder}/owner` | +| Claude 플랫폼 프롬프트 | `prompts/claude-platform.md` | +| reviewer 프롬프트 | `prompts/claude-paired-room.md` | +| arbiter 프롬프트 | `prompts/arbiter-paired-room.md` | +| Codex 플랫폼 프롬프트 | `prompts/codex-platform.md` | +| 글로벌 메모리 | `groups/global/CLAUDE.md` | + +## 문서와 실제 코드의 우선순위 + +문서보다 실제 동작이 우선입니다. 동작 기준을 확인할 때는 아래를 먼저 봅니다. + +1. `.env.example` +2. `src/config/load-config.ts` +3. `src/agent-runner-environment.ts` +4. `src/paired-execution-context.ts` diff --git a/package.json b/package.json index ee64dad..bf43fa2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ejclaw", - "version": "0.1.0", - "description": "Personal Claude assistant. Lightweight, secure, customizable.", + "version": "0.2.0", + "description": "Discord tribunal multi-agent assistant with owner, reviewer, and arbiter roles.", "packageManager": "bun@1.3.11", "type": "module", "main": "dist/index.js",