Files
hanarang-rails/README.md
이랑이 8c123cb03a feat(v0.1.3): LLM 어댑터 + in-process 모드 + docker-compose — 외부인 배포 친화
## LLM 공급자 어댑터 (B)

- sister-agent/src/llm/ 에 LlmAdapter 인터페이스 신설. 어댑터 5종:
    openclaw (기존), openai, anthropic, ollama, mock
- 선택은 LLM_PROVIDER 환경변수로. 기본값 mock.
- 모델명은 LLM_MODEL_{MANAGER,PRINCIPAL,LEAD,JUNIOR} 로 외부화.
  OpenClaw 내부 네이밍이 기본값이지만 env 로 얼마든지 갈아끼움.
- openai 어댑터는 OPENAI_BASE_URL 로 OpenRouter / Azure / 로컬 llama.cpp
  서버까지 커버.

## In-process 단일 프로세스 모드 (C)

- sister-agent/src/core.ts 로 executeInvocation 을 library-export
- rails 에 InProcessTransport 추가. 동적 import 로 sister-agent core 를
  로드해 같은 Node 프로세스에서 함수 호출로 실행.
- DirectRailsClient 로 HTTP 루프백 없이 DB 에 직접 쓰기 — 단일
  프로세스에서도 observability 동일.
- RailsConfig 에 transport: "in-process" 추가.
- buildTransports 가 RAILS_TRANSPORT 와 per-stage override 를 지원하도록
  확장. 레거시 RAILS_TRANSPORT_MODE + RAILS_AGENT_*_HOST 도 그대로 호환.

## Git push 외부화 + allowlist env 화

- spawn.ts 의 ENABLE_GIT_PUSH 를 "GITEA_TOKEN 있으면 auto on" 으로 변경.
  기존 Dev 토폴로지는 sister LXC 들에 이미 토큰이 있어서 행동 변화 없음.
- rails.service.ts 의 파일 프록시 allowlist 를 GIT_RAW_ALLOWED_HOSTS
  env 로 외부화. 기본값은 기존 Gitea 호스트 유지.

## Docker / 배포

- Dockerfile 추가. 단일 이미지로 rails + sister-agent 둘 다 빌드.
- docker-compose.yml (기본): mariadb + rails 한 컨테이너 = in-process.
  docker compose up 한 줄로 로컬 E2E 가능.
- docker-compose.full.yml: rails + 4 개 독립 sister 컨테이너 = 분산.

## 설정 샘플 + 문서

- .env.example 완전 재작성: 필수/LLM/토폴로지/Gitea/Discord 5 섹션
- rails.config.local.yaml: in-process 샘플
- rails.config.distributed.yaml: http 분산 샘플
- docs/LOCAL-SETUP.md: 30분 퀵스타트 (Docker + 네이티브 두 경로)
- README 에 "5분 퀵스타트" + 토폴로지 표 + LLM 공급자 목록 추가

## 테스트

- tests/transport-build.test.ts (6 테스트): 기본값 / in-process /
  per-stage override / http 엔드포인트 누락 / env 기반 wiring / 레거시
  env 호환
- 전체 테스트 105 → 111 통과
2026-04-10 21:51:53 +09:00

185 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# hanarang-rails
> **4 자매가 달릴 결정론적 레일** — HaNaRang Rails
>
> _사용자는 출발 버튼만 누른다. 나머지는 자매들이 자동으로 달린다._
`hanarang-rails` 는 4 개의 AI "자매" 에이전트 (하랑 / 나랑 / 다랑 / 이랑) 가 하나의 요청을 받아 **기획 → 구현 → 리뷰 → 배포**를 자동으로 완주하는 결정론적 파이프라인 오케스트레이터다. 전임자 `hanarang-harness` 가 권고 기반이라 자매들이 중간에 길을 잃던 문제를, XState 유한 상태 기계 (FSM) 와 Sprint Contract 로 물리적으로 강제한다.
- **처음 보는 사람을 위한 완전 가이드**: [`docs/GUIDE.md`](docs/GUIDE.md) / [`docs/GUIDE.pdf`](docs/GUIDE.pdf)
- **설계 문서**: [`.plans/design/`](.plans/design/)
- **스프린트 명세**: [`.plans/sprints/`](.plans/sprints/)
- **실패 감사 (F1F6)**: [`.plans/failure-audit.md`](.plans/failure-audit.md)
---
## 한 문단 요약
사용자가 `"todo 앱 만들어 줘"` 한 줄을 던지면, rails 오케스트레이터가 **하랑이 (기획) → 나랑이 (구현) → 다랑이 (리뷰) → 이랑이 (배포)** 순서로 파이프라인을 돌린다. 각 자매는 내부에서 **부장/수석/선임/신입** 4 단계 계층으로 태스크를 쪼개서 병렬 실행하고, 만들어낸 코드 파일은 자동으로 Gitea 에 public repo 로 push 되어 즉시 접근 가능한 URL 로 바뀐다. 대시보드에서는 이 모든 과정이 실시간으로 트리 형태로 보인다.
## 왜 다시 만들었는가
[`hanarang-harness`](https://git.nabomhalang.co.kr/hanarang/openclaw-harness) 에서 4 개월 운영하며 발견한 6 가지 고질 실패 모드:
| 코드 | 증상 | 원인 |
|---|---|---|
| F1 | 하네스 skill bypass — 자매가 혼자 worker 스폰 | skill 진입 강제 없음 |
| F2 | DoD 자동 강제 실패 — `build` 통과 = 완료로 판정 | sprint contract / validator 없음 |
| F3 | QA 단계 누락 — 사용자가 수동으로 다랑이 호출 | 자동 라우팅 없음 |
| F4 | 핸드오프 멘션 불안정 — 잘못된 자매 호출 | 분기가 LLM 판단에 의존 |
| F5 | 중간 끊김 — `request-timed-out` 반복 | 재시도/에스컬레이션 정책 없음 |
| F6 | 환경 검증 누락 — "Docker 없음" 으로 skip 허용 | 환경 전제 검사 없음 |
본질 한 줄: **"자매가 하네스를 안 타고 본인이 처리한다."**
## 6 가지 설계 원칙 (하드 룰)
1. **강제 > 권고** — 모든 파이프라인 전이는 코드로 강제한다.
2. **결정론적 FSM** — 자매 간 핸드오프는 XState 상태 전이다.
3. **Sprint Contract = 불변 계약** — DoD 를 Zod 스키마로 정의, validator 가 pass/fail 판정.
4. **Skill 강제 진입** — skill bypass 를 hook 이 감지해 차단.
5. **QA 체크리스트 의무** — 다랑이가 체크박스 전부 채워야 PASS.
6. **환경 검증 선행** — 실기동 검증 환경 없으면 스프린트 시작 자체를 거부.
## 아키텍처 개요
```
사용자 (Discord / Dashboard Web)
┌─────────────────────────────┐
│ hanarang-dashboard │ Next.js 16 + NestJS
│ /rails, /office, /sisters │
└────────────┬────────────────┘
│ HTTP
┌─────────────────────────────┐
│ hanarang-rails orchestrator │ XState + Prisma + MariaDB
│ FSM ─ Contract ─ Hierarchy │
└────────────┬────────────────┘
│ HTTP invoke
┌──────────┼──────────┬──────────┐
▼ ▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│하랑 │ │나랑 │ │다랑 │ │이랑 │ sister-agent × 4 LXC
│plan │ │impl │ │review│ │deploy│
└──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘
└─────────┴─ openclaw CLI ────┘ (LLM: gpt-5.4 등)
┌───────────────┐
│ Gitea SSOT │ git.nabomhalang.co.kr
│ (auto-push) │ public repo per pipeline
└───────────────┘
```
## 기술 스택
| 레이어 | 선택 |
|---|---|
| 런타임 | Node 22 + TypeScript strict |
| 상태 머신 | XState v5 |
| 스키마 | Zod |
| DB | MariaDB (Prisma) |
| 프로세스 | execa + AbortController |
| CLI | citty |
| 로그 | pino |
| 테스트 | Vitest |
| 프론트엔드 (대시보드) | Next.js 16 + styled-components |
| 백엔드 (대시보드) | NestJS + Socket.IO |
## 상태
- **v0.1.0** — Sprint 000~007 완료. FSM / Contract / QA / Migration 코어. 105 테스트 통과.
- **v0.1.1** — 실 LLM 통합 (OpenClaw infer), 4 계층 재귀 스폰, 파일 추출, Gitea auto-push, deploy URL.
- **v0.1.2** — 대시보드 아티팩트 뷰, FileViewerModal (MD 파일 클릭 → 모달).
- **v0.1.3** — LLM 제공자 어댑터 (OpenAI / Anthropic / Ollama / OpenClaw / mock), in-process 단일 프로세스 모드, docker-compose, Gitea 호스트 완전 외부화, 외부 배포 친화 .env.example.
## 빠른 시작 (Docker, 5 분)
가장 짧은 경로. 로컬에 `docker``docker compose` 만 있으면 된다.
```bash
git clone https://git.nabomhalang.co.kr/hanarang/hanarang-rails.git
cd hanarang-rails
cp .env.example .env
# .env 에서 LLM_PROVIDER=mock 으로 시작 (또는 openai/anthropic/ollama)
docker compose up --build
# → http://localhost:18800/health 확인
# 다른 터미널
curl -X POST http://localhost:18800/pipelines/start \
-H 'content-type: application/json' \
-d '{"project":"hello","requirements":"Say hi"}'
```
이게 끝. MariaDB + rails + sister-agent 4 개가 한 컨테이너 안에서 **in-process 모드** 로 돈다. 자세한 설정 옵션 (실제 LLM 키 연결, 네이티브 설치, 분산 토폴로지, 대시보드) 은 [`docs/LOCAL-SETUP.md`](docs/LOCAL-SETUP.md) 참조.
### 배포 토폴로지
| 모드 | 설명 | 파일 |
|---|---|---|
| **in-process** | 모든 것을 하나의 Node 프로세스에서. 로컬 개발 기본값 | `docker-compose.yml` · `rails.config.local.yaml` |
| **http 분산** | rails + 4 개 독립 sister-agent 컨테이너. 운영 토폴로지 | `docker-compose.full.yml` · `rails.config.distributed.yaml` |
| **mock** | FSM 만 검증 (LLM/파일/push 없음) | `RAILS_TRANSPORT=mock` 또는 `rails run --mock` |
### LLM 제공자
어댑터가 있어 다음 중 하나를 선택할 수 있다. `.env``LLM_PROVIDER` 로 지정:
- `mock` — API 키 없이 결정론 스켈레톤만 확인 (기본값)
- `openai` — OpenAI / OpenRouter / Azure OpenAI / OpenAI-호환 로컬 서버
- `anthropic` — Anthropic Messages API
- `ollama` — 로컬 Ollama 서버
- `openclaw` — hanarang 내부 전용 런타임
## CLI 서브커맨드
| 명령 | 용도 |
|---|---|
| `rails start` | 파이프라인 생성 |
| `rails run [--mock]` | E2E 실행 |
| `rails status [id]` | 상태 조회 + 타임라인 |
| `rails resume <id>` | escalated → idle 재개 |
| `rails abort <id>` | 강제 종료 |
| `rails contract generate/freeze/validate/show` | Sprint Contract 관리 |
| `rails qa run/show/templates` | QA 템플릿 실행 |
| `rails skill-context create/show/clear` | Skill 강제 진입 |
| `rails skill-trace show/blocked` | 도구 사용 감사 로그 |
| `rails doctor` | 환경 헬스체크 |
| `rails scaffold` | 신규 프로젝트 `.plans/` 생성 |
| `rails migrate from-hanarang-harness <path>` | 레거시 하네스 스캔 |
| `rails serve` | 오케스트레이터 HTTP 서버 |
## HTTP API (orchestrator, 18800)
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | `/health` | 헬스체크 |
| GET | `/pipelines?limit=N` | 파이프라인 리스트 |
| GET | `/pipelines/:id` | 파이프라인 상세 |
| POST | `/pipelines/start` | 새 파이프라인 실행 |
| POST | `/pipelines/:id/abort` | 강제 종료 |
| GET | `/api/pipelines/:id/sub-tasks` | SubTask 트리 |
| GET | `/api/sub-tasks/:id` | 서브태스크 상세 |
| GET | `/api/transitions` | 상태 전이 이력 |
| GET | `/api/escalations` | 에스컬레이션 큐 |
## 문서
- [`docs/LOCAL-SETUP.md`](docs/LOCAL-SETUP.md) — **30 분 퀵스타트** (본인 환경에서 처음 돌려 보기)
- [`docs/GUIDE.md`](docs/GUIDE.md) — **완전 가이드** (전 구간 해설, 처음 보는 사람용)
- [`docs/GUIDE.pdf`](docs/GUIDE.pdf) — 위 문서의 PDF 버전
- [`docs/migration-guide.md`](docs/migration-guide.md) — 레거시 → rails 이전 가이드
- [`docs/operations.md`](docs/operations.md) — 운영 가이드 (PM2, 로그, DB)
- [`docs/discord-setup.md`](docs/discord-setup.md) — Discord 봇 연동 + marker 프로토콜
- [`.plans/OVERVIEW.md`](.plans/OVERVIEW.md) — 프로젝트 전체 개요
- [`.plans/failure-audit.md`](.plans/failure-audit.md) — F1F6 실패 감사
- [`.plans/design/`](.plans/design/) — 설계 문서 9 종
- [`.plans/sprints/`](.plans/sprints/) — 스프린트 상세
## 라이선스
MIT — 나봄하랑 / hanarang