# 자동화 오케스트레이터 에이전트 설계서
> 버전: 1.0 | 작성일: 2026-03-24 | 승인: task-899.1 에이전트 미팅 만장일치 합의

---

## 1. 개요

### 목적
사람 개입 없이 사전 정의된 파이프라인을 자율 실행하는 자동화 에이전트 아키텍처.

### 핵심 원칙
1. **기존 코드 무수정**: chain.py, dispatch.py, notify-completion.py의 코드를 한 줄도 수정하지 않음
2. **토큰 0**: 오케스트레이션 자체는 Claude 세션을 사용하지 않음 (순수 Python)
3. **보안 우선**: 로키 6개 최소 보안 기준 + 펜리르 P0 4건 전부 MVP에 포함
4. **아누와 독립 피어**: 아누의 하위 에이전트가 아님, 충돌 방지 메커니즘 내장

### 현재 → 목표 아키텍처

```
[현재] 제이회장님 → 아누(수동 트리거) → 팀장들 → 팀원들
       ※ 정해진 흐름(A→B→C)도 아누가 매번 판단·위임 필요

[목표] 제이회장님 → 아누 (판단 필요 작업)
                      ↕
                auto_orch (정해진 파이프라인 자율 실행) → 팀/에이전트들
```

---

## 2. 아키텍처

### 2-1. 에이전트 형태

**30초 주기 systemd timer + stateless Python 스크립트**

```
systemd timer (30초마다)
  → auto_orch.py --scan
    → pipelines/ 스캔 → 트리거 조건 평가
    → 조건 충족 → 파이프라인 시작 (chain.py + dispatch.py 호출)
    → 진행 중 파이프라인 상태 확인 → 다음 스텝 진행
    → 타임아웃/에러 감지 → Telegram 알림
  → 프로세스 종료 (상태는 파일에 저장됨)
```

### 2-2. 아누와의 관계

```
제이회장님
    ├── 아누 (대화형, 즉흥 판단)
    │       ↓ dispatch.py
    │     팀장들
    │
    └── auto_orch (자동화, 사전 정의)
            ↓ chain.py + dispatch.py
          팀장들

    공유: dispatch.py, chain.py, .done protocol, task-timers.json
    충돌 방지: TeamLock (fcntl.flock 기반 팀별 뮤텍스)
```

**3가지 관계 원칙:**
1. 아누가 auto_orch를 호출 가능 (`auto_orch.py --run <pipeline_id>`)
2. auto_orch가 아누에게 보고 (Telegram Direct API, 0 토큰)
3. 동일 팀 동시 접근 시 TeamLock이 후발 프로세스를 거부

### 2-3. 기존 시스템 통합

```
auto_orch.py (신규)
    │
    ├── chain.py create + add-phase (subprocess, 무수정)
    ├── dispatch.py --team --task-file (subprocess, 무수정)
    │
    └── .done 이벤트 소비 (event_bus.py 경유)
              ↑
         finish-task.sh (기존 그대로)
              ↑
         notify-completion.py (기존 그대로)
```

---

## 3. 컴포넌트 상세

### 3-1. auto_orch.py (메인 오케스트레이터, ~300 LOC)

```
Usage:
    python3 auto_orch.py --scan          # 트리거 스캔 + 진행 (timer 호출)
    python3 auto_orch.py --run <id>      # 특정 파이프라인 수동 시작
    python3 auto_orch.py --status        # 실행 중 파이프라인 조회
    python3 auto_orch.py --list          # 등록된 파이프라인 목록
    python3 auto_orch.py --validate <f>  # YAML 검증만 수행
```

**핵심 로직 (--scan):**
1. `pipelines/*.yaml` 로드 → `pipeline_validator.py`로 전수 검증
2. 각 파이프라인 트리거 조건 평가 (event/schedule/manual)
3. 트리거 충족 + 미실행 중 → 파이프라인 시작
4. 진행 중 파이프라인: 현재 스텝 완료 확인 → 게이트 확인 → 다음 스텝 dispatch
5. 타임아웃 감지 → Telegram 알림

### 3-2. pipeline_validator.py (검증기, ~80 LOC)

**검증 항목 (로드 시 전부 통과 필수):**
1. `schema_version` 존재 + 지원 버전
2. `gates` 최소 1개 이상
3. `token_budget` 존재 + 양수
4. `blast_radius` 유효값 ("step" | "team" | "org")
5. `allowed_teams` 비어있지 않음
6. `validate_dag()` 통과 (Kahn's algorithm으로 순환 검출)
7. `scan_secrets()` 통과 (시크릿 패턴 탐지 시 거부)
8. 모든 `target_team`이 `allowed_teams` 내에 존재
9. 모든 `depends_on` 참조가 유효한 step id
10. `task_desc` 필드 전부 `injection_guard()` 통과

### 3-3. event_bus.py (이벤트 소비, ~50 LOC)

**원자적 .done 이벤트 소비:**
```python
# POSIX rename()으로 단일 소비 보장
os.rename(incoming/task-X.done, processed/task-X.done)
# FileNotFoundError → 다른 소비자가 선점 → 정상 스킵
```

### 3-4. token_ledger.py (토큰 예산, ~60 LOC)

- **DAILY_HARD_LIMIT**: 1,000,000 tokens
- **PIPELINE_DEFAULT**: 파이프라인 미설정 시 기본 token_budget
- **MAX_CONCURRENT_PIPELINES**: 3
- **MAX_RETRIES_PER_STEP**: 2 (지수 백오프: 30s → 60s → 120s)
- **MAX_PIPELINE_STARTS_PER_DAY**: 20 (동일 pipeline_id 기준)

### 3-5. TeamLock (팀 뮤텍스)

```python
class TeamLock:
    """fcntl.flock 기반 팀별 배타적 접근 제어.
    Anu와 auto_orch 중 하나만 동일 팀에 dispatch 가능."""

    def __enter__(self):
        fcntl.flock(self._fh, fcntl.LOCK_EX | fcntl.LOCK_NB)
        # BlockingIOError 시 → 해당 팀 스킵 (다음 tick에서 재시도)
```

---

## 4. 파이프라인 YAML 스키마

```yaml
# 스키마 버전 1.0
schema_version: "1.0"

id: "marketing-dev-pipeline"           # [a-z0-9\-]+ 필수
name: "마케팅 → 개발 파이프라인"
description: "GA4 추적 설계 → Dev 구현 → QC 자동"

# === 보안 필드 (전부 필수) ===
allowed_teams: ["marketing", "dev1-team", "qc"]
token_budget: 8000
blast_radius: "team"

# === 게이트 (최소 1개 필수) ===
gates:
  - id: "gate-qc"
    type: "qc_review"
    approver_role: "qc_officer"
    timeout_hours: 48

# === 롤백 ===
rollback:
  strategy: "reverse_steps"
  notify_on_rollback: true

# === 트리거 ===
triggers:
  event:
    source_team: "marketing"
    task_tag: "ga4-design"
  manual: true

# === 스텝 ===
steps:
  - id: "step-design"
    name: "GA4 설계"
    target_team: "marketing"
    task_file_template: "pipelines/templates/ga4-design.md"
    is_trigger_step: true       # 트리거 이벤트 = 이 스텝 완료
    outputs: ["memory/reports/{task_id}.md"]
    timeout_minutes: 120

  - id: "step-implement"
    name: "구현"
    target_team: "dev1-team"
    task_file_template: "pipelines/templates/ga4-impl.md"
    depends_on: ["step-design"]
    gate_before: "gate-qc"
    inject_context:
      from_step: "step-design"
      source: "memory/reports/{prev_task_id}.md"
    outputs: ["teams/dev1/ga4-tracking.py"]
    rollback_cmd: ["python3", "scripts/revert-ga4.py"]
    timeout_minutes: 180

  - id: "step-qc"
    name: "QC 검증"
    target_team: "qc"
    task_file_template: "pipelines/templates/qc-verify.md"
    depends_on: ["step-implement"]
    timeout_minutes: 60

# === 에러 처리 ===
on_error:
  action: "notify_telegram"
  max_retries: 1

on_complete:
  action: "notify_telegram"
  message: "파이프라인 {pipeline_id} 완료"
```

---

## 5. 유스케이스별 적용

### UC-1: 마케팅 → 개발 파이프라인
- 트리거: marketing 팀의 ga4-design 태그 .done 이벤트
- 흐름: 설계(트리거 스텝) → QC 게이트 → Dev 구현 → QC 검증
- 토큰: Sonnet 2세션 (~70,000 tokens)

### UC-2: 콘텐츠 파이프라인
- 트리거: manual (Anu가 `--run content-pipeline`)
- 흐름: Apollo 초안 → Peito 리뷰 → Eirene SEO → 발행(script 타입)
- 토큰: Sonnet 3세션 (~105,000 tokens), 발행은 0토큰

### UC-3: ThreadAuto 일일 자동화
- 트리거: schedule (`0 8 * * *` 매일 오전 8시)
- 흐름: 주제 선정 → 콘텐츠 생성 → 팩트체크 → 발행
- 토큰: Sonnet 3세션 + script 발행, ~105,000 tokens/일

### UC-4: 멀티팀 스킬 실행 (CRO/Growth)
- 트리거: manual 또는 event
- 흐름: 마케팅(전략/설계) → 개발(기술 구현) 체이닝
- 토큰: 파이프라인별 상이, token_budget으로 관리

---

## 6. 보안 아키텍처

### 6-1. 방어 계층

| 계층 | 방어 대상 | 메커니즘 |
|------|-----------|----------|
| L1 입력 검증 | 악성 YAML, 인젝션 | pipeline_validator, injection_guard 하드블록 |
| L2 접근 제어 | 팀 충돌, 권한 상승 | TeamLock, allowed_teams, gates |
| L3 자원 제한 | 토큰 폭주, 무한루프 | token_ledger, DAG 검증, MAX_CONCURRENT |
| L4 감사 추적 | 사후 분석 | audit log (JSONL), security.log |
| L5 롤백 | 장애 복구 | rollback_cmd 역순 실행 |

### 6-2. 로키 6대 최소 보안 기준 충족 현황

| # | 기준 | 구현 컴포넌트 | 상태 |
|---|------|--------------|------|
| 1 | 팀별 뮤텍스 | TeamLock (fcntl.flock) | MVP |
| 2 | YAML gate 필수 | pipeline_validator | MVP |
| 3 | DAG 검증 | validate_dag() | MVP |
| 4 | 일일 토큰 한도 | token_ledger.py | MVP |
| 5 | 시크릿 분리 | scan_secrets() + env:// | MVP |
| 6 | 단일 .done 이벤트 버스 | event_bus.py | MVP |

### 6-3. 펜리르 P0 대응 현황

| # | 위협 | 대응 | 상태 |
|---|------|------|------|
| 1-A | 프롬프트 인젝션 | injection_guard 하드블록 | MVP |
| 1-B | 셸 인젝션 | shell=False + shlex.quote | MVP |
| 9-A | 토큰 소진 공격 | DAILY_HARD_LIMIT + MAX_CONCURRENT | MVP |
| 2-A | 무한 세션 루프 | MAX_RETRIES + 지수 백오프 | MVP |

---

## 7. 디렉토리 구조

```
/home/jay/workspace/
├── pipelines/                          # 파이프라인 YAML 정의 (읽기 전용)
│   ├── marketing-dev-pipeline.yaml
│   ├── content-pipeline.yaml
│   ├── threadauto-daily.yaml
│   ├── templates/                      # task_file 템플릿
│   │   ├── ga4-design.md
│   │   └── ga4-impl.md
│   └── quarantine/                     # 검증 실패 격리
│
├── orchestrator/                       # auto_orch 전용 작업 공간
│   ├── auto_orch.py                    # 메인 (~300 LOC)
│   ├── pipeline_validator.py           # 검증 (~80 LOC)
│   ├── event_bus.py                    # 이벤트 소비 (~50 LOC)
│   ├── token_ledger.py                 # 토큰 예산 (~60 LOC)
│   ├── state/                          # 실행 상태 (JSON)
│   ├── locks/                          # 팀 뮤텍스
│   ├── incoming/                       # .done 이벤트 수신
│   ├── processed/                      # 처리 완료 이벤트
│   ├── gates/                          # 게이트 승인 파일
│   │   └── {pipeline_id}/
│   │       └── {gate_id}.approved
│   ├── token_ledger.json
│   └── logs/
│       ├── auto_orch.log
│       └── security.log
```

---

## 8. 토큰 경제성

### 8-1. 현재 vs auto_orch 비용 비교

```
[현재 - 아누 수동 체이닝]
  마케팅→Dev→QC 3단계:
  - 아누 깨움 2회 × ~8,000 tokens (Opus) = 16,000 tokens
  - 비용: ~$1.20/실행 (Opus $15/$75 per 1M)

[auto_orch - 자동 체이닝]
  동일 3단계:
  - 오케스트레이션: 0 tokens (Python only)
  - 비용: $0/실행

  절감: 100% (오케스트레이션 비용만 기준)
```

### 8-2. 예산 한도

- **DAILY_HARD_LIMIT**: 1,000,000 tokens (~$18/일 Sonnet 기준)
- **MAX_CONCURRENT_PIPELINES**: 3
- **파이프라인별 token_budget**: YAML에서 개별 설정
- **MAX_PIPELINE_STARTS_PER_DAY**: 20 (동일 ID 기준)
- **MAX_RETRIES_PER_STEP**: 2

---

## 9. 모니터링

### 9-1. 헬스 파일
```json
// orchestrator/health.json (매 tick 갱신)
{
  "last_tick": "2026-03-24T09:30:00+09:00",
  "active_pipelines": 2,
  "completed_today": 7,
  "failed_today": 0,
  "daily_tokens_used": 425000,
  "daily_token_limit": 1000000
}
```

### 9-2. 알림

- 파이프라인 완료 → Telegram (Direct API, 0 토큰)
- 파이프라인 실패 → Telegram + security.log
- 토큰 80% 도달 → Telegram 경고
- 스텝 타임아웃 → Telegram + state/ 상태 갱신

---

## 10. 구현 계획

### Phase 1: MVP (로키 보안 기준 전부 포함)

| 파일 | 규모 | 핵심 기능 |
|------|------|-----------|
| auto_orch.py | ~300 LOC | 메인 루프, TeamLock, 트리거, 디스패치 |
| pipeline_validator.py | ~80 LOC | DAG, 시크릿, 게이트, 스키마 검증 |
| event_bus.py | ~50 LOC | 원자적 .done 소비 |
| token_ledger.py | ~60 LOC | 일일 한도, 파이프라인별 예산 |
| auto-orch.timer | 설정 | systemd 30초 타이머 |
| injection_guard 패치 | ~10 LOC | 하드블록 격상 |
| 총계 | ~500 LOC | |

### Phase 2: 안정화
- rollback_cmd 역순 실행 로직
- blast_radius 기반 영향 범위 제한
- 토큰 대시보드 (HTML 리포트)
- 동시 파이프라인 설정 UI

### Phase 3: 확장 (필요 시)
- SQLite 마이그레이션
- Vault 통합
- 웹훅 게이트 승인
- 멀티노드 지원

---

## 11. task-897.1과의 관계

task-897.1(1팀 설계 완료)은 `.done` 자동 감지 메커니즘:
- **Primary**: notify-completion.py → Direct Telegram API (0 토큰)
- **Fallback**: done-watcher.sh 강화 (원자적 mv 처리)

auto_orch는 task-897.1 결과를 다음과 같이 활용:
1. `.done` 파일 원자적 처리 패턴 (mv-based TOCTOU 방어)을 event_bus.py에 동일 적용
2. Direct Telegram API를 알림에 재활용
3. bot-activity.json 봇 상태를 TeamLock과 연동 가능 (Phase 2)

---

*설계서 종료 — 에이전트 미팅 만장일치 합의 기반, 2026-03-24*
