docs(isolation): commit session isolation design documents and guidelines
This commit is contained in:
@@ -122,8 +122,12 @@ TMUX 환경에서 실행되는 에이전트가 화면 스크롤 한계로 인해
|
||||
- **핵심 원칙**: TMUX `send-keys`나 입력 버퍼를 통해 긴 지시사항을 직렬로 입력하는 과정에서 문자 누락이나 레이아웃 유실이 발생하는 것을 방지하기 위해, 에이전트 간의 모든 주요 협업 소통은 파일 기반 마크다운 문서 생성을 원칙으로 합니다.
|
||||
- **세부 규칙 및 규약**:
|
||||
- **예외 사항**: 1~2줄 내외의 매우 단순한 재평가 요청, 상태 확인, 수락 진행 등의 단발성 프롬프트는 기존처럼 tmux 입력을 통해 직접 보낼 수 있습니다.
|
||||
- **작업 위임**: 상세 사양과 계획 수립 등의 복잡한 작업 지시는 먼저 로컬 마크다운 파일(예: `.mam/jobs/brief-<job_id>.md` 또는 지정된 워크스페이스 경로)로 작성한 후, 에이전트에게 `"Read <파일경로> and execute."` 라는 단순화된 실행 명령만 전달하십시오.
|
||||
- **결과 안내 및 피드백**: 상세 리뷰 결과, 설계 제안서, 구현 완료 리포트 및 감사 주석 등은 반드시 마크다운 파일로 영속화하여 제공해야 합니다. 모든 에이전트는 `.mam/jobs/<agent_name>/` 아래에 자신만의 전용 디렉터리를 생성하고, 자신의 작업 결과 보고 마크다운 파일은 해당 디렉터리 내부에 저장해야 합니다 (예: `.mam/jobs/<agent_name>/report-<job_id>.md`). 수신 에이전트는 잘린 터미널 화면 캡처에 의존하는 대신 디스크에서 해당 파일을 직접 로드하여 확인합니다.
|
||||
- **작업 위임**: 상세 사양과 계획 수립 등의 복잡한 작업 지시는 먼저 로컬 마크다운 파일(예: `.mam/reports/brief-<job_id>.md` 또는 지정된 워크스페이스 경로)로 작성한 후, 에이전트에게 `"Read <파일경로> and execute."` 라는 단순화된 실행 명령만 전달하십시오.
|
||||
- **결과 안내 및 피드백**: 상세 리뷰 결과, 설계 제안서, 구현 완료 리포트 및 감사 주석 등은 반드시 마크다운 파일로 영속화하여 제공해야 합니다. 기계 전용인 잡 레지스트리 평면(`.mam/jobs/`)과의 물리적 분리를 위해, 모든 에이전트는 `.mam/reports/<tmux_session_name>/` 아래에 전용 디렉터리를 형성하고 결과 보고 마크다운 파일을 저장해야 합니다 (여기서 `<tmux_session_name>`은 `.mam/agent-sessions.yaml`의 `name` 필드와 완전히 일치해야 합니다. 예: `.mam/reports/<workspace_slug>-creator-<agent>/report-<job_id>.md`). 수신 에이전트는 잘린 터미널 화면 캡처에 의존하는 대신 디스크에서 해당 파일을 직접 로드하여 확인합니다.
|
||||
- **디스크 정리 및 보존 정책 계약 (Cleanup & Retention)**:
|
||||
- `.mam/reports/` 폴더 아래의 파일들은 감사 이력(audit-trail) 산출물로 보존됩니다.
|
||||
- 해당 격리 디렉터리들은 `stop_session.sh` 등을 통해 세션이 정상적으로 종료되거나 파기(`--purge-conversation`)될 때 자동으로 함께 정리되어야 합니다.
|
||||
- 버전 관리가 필요한 영구 보존용 주요 산출물(최종 설계 계획, 보안 감사 리포트 등)은 gitignore 대상인 `.mam/` 하위가 아닌, 버전 관리 대상 경로(예: `docs/` 또는 `artifacts/` 등)로 명시적으로 복사하여 기록을 이관 보존해야 합니다.
|
||||
|
||||
### ⏱️ 타임아웃 구성 및 정렬 규칙
|
||||
- **잡 실행 제한 (`timeout_sec` & `idle_timeout_sec`)**: 각 잡은 전체 실행 만료 시간(`timeout_sec`, 기본 3600s)과 메세지 미수신 유휴 시간(`idle_timeout_sec`, 기본 120s)을 독립적으로 가집니다.
|
||||
|
||||
@@ -122,8 +122,12 @@ To ensure that agents running in TMUX environments do not lose debug logs or pre
|
||||
- **Core Principle**: To prevent TUI character loss, truncation, and layout breakage during sequential input typing, all collaborative workflows must favor file-based markdown communication.
|
||||
- **Rules & Protocols**:
|
||||
- **Exception**: Extremely simple prompts (e.g., "Re-evaluate", "Check status", "Proceed") of 1 or 2 lines may be sent directly via tmux input buffers.
|
||||
- **Task Delegation**: All detailed task briefs, specifications, and instructions must be written to a local Markdown file (e.g., `.mam/jobs/brief-<job_id>.md` or a workspace path) first. The sender then issues a simple trigger command: `"Read <file_path> and execute."`
|
||||
- **Result Reporting & Feedback**: All detailed review results, design proposals, implementation reports, and audit comments must be saved as Markdown files. Every agent must create a dedicated directory for itself under `.mam/jobs/<agent_name>/` and save its job output/report Markdown files inside this folder (e.g., `.mam/jobs/<agent_name>/report-<job_id>.md`). The recipient reads these files directly from disk instead of relying on truncated terminal screen captures.
|
||||
- **Task Delegation**: All detailed task briefs, specifications, and instructions must be written to a local Markdown file (e.g., `.mam/reports/brief-<job_id>.md` or a workspace path) first. The sender then issues a simple trigger command: `"Read <file_path> and execute."`
|
||||
- **Result Reporting & Feedback**: All detailed review results, design proposals, implementation reports, and audit comments must be saved as Markdown files. To separate human-readable documents from the machine job registry (`.mam/jobs/`), every agent must save its outputs under `.mam/reports/<tmux_session_name>/` (using the full tmux session name matching the `name` field in `.mam/agent-sessions.yaml`, e.g., `.mam/reports/<workspace_slug>-creator-<agent>/report-<job_id>.md`) to ensure strict isolation across multiple roles/instances.
|
||||
- **Cleanup & Retention Contract**:
|
||||
- Files under `.mam/reports/` are audit-trail artifacts.
|
||||
- These folders should be cleaned up automatically during `stop_session.sh` when a session is gracefully stopped or purged (`--purge-conversation`).
|
||||
- Durable outcomes (such as final design plans or security audit reports) that require version control must be explicitly copied to tracked directory paths (e.g., `docs/` or `artifacts/`) instead of remaining in the gitignored `.mam/` runtime tree.
|
||||
|
||||
### ⏱️ Timeout Configuration & Alignment Rules
|
||||
- **Job Execution Limits (`timeout_sec` & `idle_timeout_sec`)**: Each job independently manages its overall execution timeout (`timeout_sec`, default 3600s) and idle timeout without receiving messages (`idle_timeout_sec`, default 120s).
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
# Multi-Agent Collaboration Workflow Reference Guide
|
||||
|
||||
본 문서는 대규모 프로젝트나 정밀한 설계·구현 요구사항을 처리하기 위해 **Planner, Developer, Reviewer** 에이전트 간의 역할 분담 및 피드백 루프를 운영하는 **다중 에이전트 협업 워크플로우(Multi-Agent Collaboration Workflow)**를 정의합니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 역할 정의 및 분담 (Roles & Responsibilities)
|
||||
|
||||
협업 시스템은 각 에이전트의 책임 영역을 명확히 격리하여 상호 교차 검증을 강제합니다.
|
||||
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ User Prompt │
|
||||
└──────────┬───────────┘
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ 1. Planner Agent │ ◄──────────────────┐
|
||||
│ - Plan & Checklist │ │
|
||||
└──────────┬───────────┘ │
|
||||
▼ │
|
||||
┌──────────────────────┐ │
|
||||
│ 2. Developer Agent │ │
|
||||
│ - Code & DoD Verify │ │
|
||||
└──────────┬───────────┘ │
|
||||
▼ │ (NOT PASS Feedback)
|
||||
┌──────────────────────┐ │
|
||||
│ 3. Reviewer Agents │ │
|
||||
│ - Dual Peer Review │ ───────────────────┘
|
||||
└──────────┬───────────┘
|
||||
▼ (PASS)
|
||||
┌──────────────────────┐
|
||||
│ 4. Done & Commit │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
### 1.1. Planner Agent (설계 및 통제)
|
||||
- **목적**: 요구사항을 명세화하고, 구현 단계의 설계 결함이나 모순(Contradiction)을 사전에 차단합니다.
|
||||
- **역할**:
|
||||
- 사용자 요구사항에 따른 구현 목표 및 범위 수립.
|
||||
- `implementation_plan.md` 및 `task.md` (체크리스트) 작성 및 버전 관리(Rev.1, Rev.2, ...).
|
||||
- 리뷰어 피드백 발생 시 설계 변경의 파급 범위를 계산하여 계획 갱신.
|
||||
- **핵심 원칙**: 직접 코드를 수정하지 않고 오직 설계와 체크리스트 자산만 관리합니다.
|
||||
|
||||
### 1.2. Developer Agent (구현 및 자가 검증)
|
||||
- **목적**: Planner가 제공한 체크리스트를 기반으로 실제 리포지토리 코드를 물리적으로 수정 및 구현합니다.
|
||||
- **역할**:
|
||||
- `task.md`를 순차적으로 완료 상태(`[x]`)로 업데이트하며 구현 수행.
|
||||
- 커밋 전 **Definition of Done (DoD)** 체크리스트를 자체 실행하여 금지된 코드 패턴, 메모리/구조적 사이드 이펙트 유무 자가 검토.
|
||||
- 수정 사항을 단일 원자적(Atomic) 커밋으로 마감하고 리뷰어에게 전달.
|
||||
|
||||
### 1.3. Reviewer Agents (교차 피드백 및 검증)
|
||||
- **목적**: 구현된 결과물이 최초 설계서 및 학술적 제약 요건에 일치하는지 제3자의 관점에서 엄격하게 검토합니다.
|
||||
- **역할**:
|
||||
- **Reviewer A (Claude)**: 학술 서사와 코드 설계 간의 상위 논리적 정합성 및 결함(예: HOLB 해소 주장과 단일 커넥션 다이얼러의 모순 등) 검증.
|
||||
- **Reviewer B (Cline)**: 전이 조건, 예외 처리, 타입 시그니처, 텔레메트리 매핑 등 하위 레벨 구현의 세부 사항 기계적 검증.
|
||||
- **판정 규칙**: 두 리뷰어 모두 **PASS** 판정을 내릴 때까지 개발자는 마감할 수 없으며, 반려 시 **1단계(Planner)**로 피드백이 환류됩니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 세부 운영 단계 (Step-by-Step Workflow)
|
||||
|
||||
### 1단계: 설계 수립 (Planning Phase)
|
||||
1. 사용자가 요구사항을 제시하면, **Planner 에이전트**가 프로젝트의 전반적인 구조를 파악합니다.
|
||||
2. `implementation_plan.md` 및 `task.md`를 작성하여 개발을 위한 로드맵을 제공합니다.
|
||||
3. 사용자가 해당 구현 계획을 승인하면 다음 단계로 이행합니다.
|
||||
|
||||
### 2단계: 코드 구현 및 자가 검증 (Development Phase)
|
||||
1. **Developer 에이전트**가 배정된 태스크의 코드를 수정합니다.
|
||||
2. 작업 진행 중 예상치 못한 설계 변경 필요성이 감지되면 작업을 멈추고 **Planner 에이전트**에게 계획 수정을 먼저 위임합니다.
|
||||
3. 구현 완료 후 아래의 **DoD 검증**을 수행합니다:
|
||||
- 핵심 기능의 타입 매핑 확인.
|
||||
- 공유 자원(`tls.Config` 등) 변경 시 사이드 이펙트 방지(복제 후 변이 적용 등).
|
||||
- 문서-코드 간 주장의 정합성 체크.
|
||||
4. 검증 완료 후 단일 커밋을 작성합니다.
|
||||
|
||||
### 3단계: 피드백 루프 및 통과 (Review Phase)
|
||||
1. Developer 에이전트가 리뷰어 세션에 작업 완료 사실과 변경 범위를 전달합니다.
|
||||
2. 리뷰어들은 `git diff`를 바탕으로 개별 검증을 수행하고 보고서 형태의 리뷰 피드백을 출력합니다.
|
||||
- **반려 (`NOT PASS`)** -> 피드백 요약본을 Planner 에이전트에게 전송하여 상위 레벨 계획(Rev.n) 개시.
|
||||
- **통과 (`PASS`)** -> 모든 검토 사항이 해결되었음을 명시.
|
||||
3. 모든 리뷰어가 PASS를 발행하면 작업을 완결하고 세션을 안전하게 종료(`multi-agent-mux-stop`)합니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. Best Practices & 템플릿
|
||||
|
||||
### 3.1. 작업 시작 시 Planner 에이전트 프롬프트 템플릿
|
||||
```
|
||||
[역할 요구]
|
||||
프로젝트의 구조 및 내용을 파악하고, 현재 작업 요건에 맞춰 구현 계획서(implementation_plan.md) 및 태스크 체크리스트(task.md)를 작성해 주세요.
|
||||
|
||||
[검토 초점]
|
||||
- 설계 수준에서 논리적 모순이 발생할 여지가 없는지
|
||||
- naive 구현과 대비되는 핵심 차별점이 코드 명세에 정확히 명시되었는지
|
||||
```
|
||||
|
||||
### 3.2. 피드백 루프 환류 시 프롬프트 템플릿
|
||||
```
|
||||
Reviewer 검토 결과 구현 코드 차원에서 아래의 블로킹(NOT PASS) 피드백이 발생했습니다.
|
||||
위 피드백을 수용하여 설계 문서를 수정하는 계획을 수립하고, implementation_plan.md (Rev.[N]) 및 task.md 내용을 업데이트해 주세요.
|
||||
|
||||
[피드백 내용]
|
||||
- [블로킹 항목 1]
|
||||
- [블로킹 항목 2]
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
# 에이전트 세션 ID 중복 충돌 분석 보고서
|
||||
|
||||
본 보고서는 `multi-agent-mux` 오케스트레이션 환경에서 동일 언어 모델 계열(Claude 및 Cline)의 서로 다른 역할 에이전트들이 동일한 세션 ID를 공유하게 된 문제를 정의하고, 이에 대한 실질적인 해결 방법을 제안합니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. Problem Definition (문제 정의)
|
||||
|
||||
### 1.1 현상
|
||||
- 현재 프로젝트 세션 데이터베이스(`.mam/agent-sessions.yaml`)를 확인한 결과, 역할이 다른 에이전트들이 동일한 고유 세션 ID를 공유하고 있습니다:
|
||||
- **Claude 계열**: `planner`와 `reviewer-a`가 동일한 대화 ID (`7ef1095f-4533-44be-ba9a-07260328f5ff`)를 공유
|
||||
- **Cline 계열**: `developer`와 `reviewer-b`가 동일한 대화 ID (`1783574535923_z770y`)를 공유
|
||||
|
||||
### 1.2 원인
|
||||
- **세션 정보 공유 방식의 한계**: Claude Code 및 Cline CLI는 동일 프로젝트 디렉터리 내에서 실행될 때 기본적으로 가장 최근에 생성되었거나 활성화된 로컬 세션 ID(캐시 파일)를 상속 및 공유하도록 설계되어 있습니다.
|
||||
- **동시 구동 시의 경쟁 상태 (Race Condition)**: 최초 온보딩 시 스크립트가 여러 에이전트를 거의 동시에(`tmux new-session` 병렬 실행) 띄우는 과정에서, 각 세션이 독자적인 신규 UUID를 발급받지 못하고 로컬의 마지막 활성 세션 정보로 진입점이 묶여버렸습니다.
|
||||
|
||||
### 1.3 영향 및 부작용
|
||||
- **컨텍스트 오염 (Context Contamination)**: 기획자(Planner)가 지시 수행 중 출력한 생각과 로그가 리뷰어(Reviewer A)의 화면에도 실시간으로 노출되는 등 역할 격리가 무너집니다.
|
||||
- **락 충돌 (Lock Conflict)**: 동일한 대화 히스토리 파일(`*.jsonl` 또는 `*.db`)에 두 에이전트 프로세스가 동시에 쓰기(Write) 작업을 시도하면서 데이터 유실 및 동작 지연이 발생합니다.
|
||||
- **검증의 객관성 상실**: 리뷰어가 본래의 독립적 검수 목적을 잃고, 개발/기획 세션의 편향된 맥락을 공유하게 됩니다.
|
||||
@@ -0,0 +1,138 @@
|
||||
# Implementation Plan — 배포 스크립트 URL 파라미터화 (Rev.1)
|
||||
|
||||
- **작성자**: Planner Agent
|
||||
- **날짜**: 2026-07-09
|
||||
- **상태**: Draft (사용자 승인 대기)
|
||||
- **관련 리뷰 피드백**: Reviewer A 이식성(portability) 스캔 결과
|
||||
|
||||
---
|
||||
|
||||
## 1. 배경 및 문제 정의
|
||||
|
||||
Reviewer A의 코드베이스 스캔 결과, 배포 스크립트에 배포 원본(origin) URL 3개가 하드코딩되어 있어
|
||||
포크/미러/사설 Gitea 인스턴스 환경으로의 이식성이 저해됨이 확인되었습니다.
|
||||
|
||||
| # | 위치 | 변수 | 현재 하드코딩 값 |
|
||||
|---|------|------|------------------|
|
||||
| 1 | `deploy/install.sh:57` | `REPO_URL` | `https://git.godopu.com/tmpl/multi-agent-mux.git` |
|
||||
| 2 | `deploy/install.sh:58` | `ARCHIVE_URL` | `https://git.godopu.com/tmpl/multi-agent-mux/archive/main.tar.gz` |
|
||||
| 3 | `deploy/update.sh:138` | `INSTALLER_URL` | `https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh` |
|
||||
|
||||
그 외 스크립트(`lib.sh`, `create_session.sh` 등)는 상대 경로 및 `TARGET_DIR` 파라미터화가
|
||||
올바르게 적용되어 있어 이번 변경 범위에서 제외합니다.
|
||||
|
||||
## 2. 목표 (Goals)
|
||||
|
||||
1. 위 3개 URL을 환경변수 `MAM_REPO_URL`, `MAM_ARCHIVE_URL`, `MAM_INSTALLER_URL`로
|
||||
오버라이드 가능하게 파라미터화하되, **미설정 시 현재 값을 그대로 기본값으로 유지**한다
|
||||
(기존 사용자에 대한 동작 변경 0).
|
||||
2. 세 변수를 `.env.example`과 `deploy/README.md`에 문서화한다.
|
||||
3. 검증 절차를 명문화하여 Developer가 DoD 자가 검증에 사용할 수 있게 한다.
|
||||
|
||||
### Non-Goals (이번 범위 제외)
|
||||
|
||||
- `README.md`/`BOOTSTRAP*.md` 본문의 원라이너 예시 URL 자체를 변수화하는 것
|
||||
(문서상의 예시는 실제 기본 배포 원본이므로 그대로 둔다).
|
||||
- deploy 스크립트가 `.env` 파일을 직접 파싱/소싱하도록 만드는 것 (§3.4 설계 결정 참조).
|
||||
- URL 간 파생 로직 (예: `MAM_REPO_URL`로부터 archive URL 자동 조립) — §3.5 참조.
|
||||
|
||||
## 3. 설계 (Design)
|
||||
|
||||
### 3.1. `deploy/install.sh` 수정
|
||||
|
||||
57–58행을 bash 기본값 확장 패턴으로 교체:
|
||||
|
||||
```bash
|
||||
REPO_URL="${MAM_REPO_URL:-https://git.godopu.com/tmpl/multi-agent-mux.git}"
|
||||
ARCHIVE_URL="${MAM_ARCHIVE_URL:-https://git.godopu.com/tmpl/multi-agent-mux/archive/main.tar.gz}"
|
||||
```
|
||||
|
||||
### 3.2. `deploy/update.sh` 수정
|
||||
|
||||
138행을 동일 패턴으로 교체:
|
||||
|
||||
```bash
|
||||
INSTALLER_URL="${MAM_INSTALLER_URL:-https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh}"
|
||||
```
|
||||
|
||||
**체이닝 전파 주의**: `update.sh`는 140–142행에서 `curl ... | bash -s --`로 새 installer를
|
||||
실행한다. 호출자가 `MAM_REPO_URL=x bash update.sh` 형태(명령 접두 대입)로 실행하면 해당
|
||||
변수는 프로세스 환경에 export되어 자식 bash에 자동 상속되므로 별도 재-export 코드는
|
||||
불필요하다. 단, 이 상속 동작이 계약임을 스크립트 주석 및 문서에 명시한다.
|
||||
|
||||
### 3.3. `.env.example` 문서화
|
||||
|
||||
새 섹션 `# deploy / distribution source`를 추가하고 기존 파일의 서식 규약
|
||||
(`#default:` 라인 + 주석 처리된 변수 예시)을 따른다. **핵심 주의 문구**를 반드시 포함:
|
||||
|
||||
> 이 변수들은 deploy 스크립트가 **프로세스 환경에서** 읽는다. `install.sh`는 워크스페이스에
|
||||
> `.env`가 생기기 전(curl 원라이너) 실행될 수 있고 deploy 스크립트는 `.env`를 파싱하지
|
||||
> 않으므로, `export MAM_REPO_URL=...` 또는 명령 접두 대입으로 전달해야 한다.
|
||||
|
||||
### 3.4. 설계 결정: `.env` 소싱을 하지 않는 이유
|
||||
|
||||
- `install.sh`는 설치 대상 디렉터리에 파일이 존재하기 전에 실행되므로 `.env` 의존이 불가능.
|
||||
- `.env`를 `source`하면 임의 셸 코드 실행 경로가 생겨 보안·부작용 리스크 발생.
|
||||
- 따라서 세 변수 모두 **환경변수 단일 경로**로 통일하고, `.env.example`에는
|
||||
"문서화 + 사용법 안내" 목적으로만 등재한다.
|
||||
|
||||
### 3.5. 설계 결정: 변수 간 파생 없음
|
||||
|
||||
`MAM_REPO_URL`에서 archive/raw URL을 자동 조립하지 않는다. Gitea(`/archive/main.tar.gz`,
|
||||
`/raw/branch/main/`)와 GitHub(`/archive/refs/heads/main.tar.gz`, `raw.githubusercontent.com`)의
|
||||
URL 스킴이 상이하여 파생 로직이 오히려 이식성을 해친다. 세 변수는 독립이며, 미러 운영 시
|
||||
**셋을 함께 설정**하도록 문서에 권고 문구를 넣는다.
|
||||
|
||||
### 3.6. `deploy/README.md` 문서화
|
||||
|
||||
"How to Install and Deploy" 섹션에 미러/포크 설치 예시를 추가:
|
||||
|
||||
```bash
|
||||
# Installing from a fork/mirror
|
||||
curl -fsSL https://my-mirror.example.com/.../install.sh \
|
||||
| MAM_REPO_URL=https://my-mirror.example.com/me/multi-agent-mux.git \
|
||||
MAM_ARCHIVE_URL=https://my-mirror.example.com/me/multi-agent-mux/archive/main.tar.gz \
|
||||
bash
|
||||
|
||||
# Updating against a mirror
|
||||
MAM_INSTALLER_URL=https://my-mirror.example.com/.../install.sh bash deploy/update.sh
|
||||
```
|
||||
|
||||
(파이프 실행 시 접두 대입은 `bash` 쪽에 붙여야 함을 예시로 보여준다.)
|
||||
|
||||
## 4. 파급 범위 및 리스크 분석
|
||||
|
||||
| 리스크 | 평가 | 완화책 |
|
||||
|--------|------|--------|
|
||||
| 기본값 오타로 기존 설치 경로 파손 | 중 | 검증 §5-3에서 기본값 문자열이 변경 전과 byte-identical한지 diff/grep으로 확인 |
|
||||
| ShellCheck 경고 (SC2154 등) | 낮음 | `${VAR:-default}` 패턴은 미정의 변수 경고 없음. CI(`gitea-ci.yml`)의 shellcheck 단계로 확인 |
|
||||
| `update.sh` 체이닝 시 오버라이드 미전파 | 중 | §3.2 상속 계약 주석 명시 + 검증 §5-5 |
|
||||
| 문서-코드 정합성 (변수명 불일치) | 낮음 | task.md DoD에 변수명 3종 교차 대조 항목 포함 |
|
||||
|
||||
## 5. 검증 절차 (Verification Steps)
|
||||
|
||||
Developer는 커밋 전 아래를 순서대로 수행하고 결과를 리뷰 요청에 첨부한다.
|
||||
|
||||
1. **문법 검사**: `bash -n deploy/install.sh deploy/update.sh` — 종료코드 0.
|
||||
2. **린트**: `shellcheck deploy/install.sh deploy/update.sh` — 신규 경고 0 (CI와 동일 조건).
|
||||
3. **기본값 무결성**: `grep -n 'MAM_\(REPO\|ARCHIVE\|INSTALLER\)_URL' deploy/*.sh` 출력에서
|
||||
`:-` 뒤 기본값 3개가 변경 전 하드코딩 문자열과 정확히 일치하는지 확인.
|
||||
4. **오버라이드 동작 (install.sh)**: 빈 스크래치 디렉터리에서
|
||||
`MAM_ARCHIVE_URL=https://127.0.0.1:1/nope.tar.gz bash deploy/install.sh <scratch-dir>`
|
||||
실행 → fetch 단계가 오버라이드된 URL로 시도하다 실패하는지 확인
|
||||
(`bash -x` 트레이스에서 `ARCHIVE_URL` 해석값 확인). **실제 워크스페이스에서 실행 금지.**
|
||||
5. **오버라이드 동작 (update.sh)**: `update.sh`는 기존 설치를 파괴적으로 제거하므로
|
||||
전체 실행 대신 `bash -x` 트레이스를 138행 부근에서 조기 중단(Ctrl-C 또는 read 삽입 없이
|
||||
확인 후 `--force` 미사용)하거나, 디스포저블 스크래치 설치본에서만 end-to-end 수행.
|
||||
최소 기준: `MAM_INSTALLER_URL` 접두 대입 시 `INSTALLER_URL` 해석값이 오버라이드와 일치.
|
||||
6. **회귀 (기본 경로)**: 리포지토리 루트에서 `bash deploy/install.sh` 재실행 →
|
||||
`check_assets_present`가 충족되어 네트워크 fetch 없이 기존과 동일하게 완료되는지 확인.
|
||||
7. **문서 정합**: `.env.example`·`deploy/README.md`에 세 변수명이 스크립트와 철자까지
|
||||
일치하게 등재되었는지 교차 확인.
|
||||
|
||||
## 6. 산출물 및 커밋 규약
|
||||
|
||||
- 변경 파일: `deploy/install.sh`, `deploy/update.sh`, `.env.example`, `deploy/README.md`
|
||||
- 단일 원자적 커밋, 메시지 제안:
|
||||
`feat(deploy): parameterize distribution URLs via MAM_*_URL env vars`
|
||||
- 완료 후 Reviewer A(논리 정합) / Reviewer B(구현 세부) 이중 리뷰 → 양측 PASS 시 마감.
|
||||
@@ -0,0 +1,141 @@
|
||||
# Implementation Plan — 세션 ID 중복 충돌 해소 / 역할별 세션 격리 (Rev.3)
|
||||
|
||||
- **작성자**: Planner Agent
|
||||
- **날짜**: 2026-07-10 (Rev.2 → Rev.3 개정)
|
||||
- **상태**: Draft (Phase 0 검증 게이트 대기 — 구현 미착수)
|
||||
- **관련 자료**: [Problem_Definition.md](Problem_Definition.md), [session_isolation_discussion.md](session_isolation_discussion.md)
|
||||
- **확정된 방향 (Rev.3)**: **all-L2 단일화** — 전 에이전트 isolation-UUID 격리 디렉터리 + 세션 row 영속화 + R1 claimed-set 불변식
|
||||
|
||||
---
|
||||
|
||||
## 0. Rev.2 → Rev.3 변경 이력 (Decision Log)
|
||||
|
||||
| # | 결정 | 사유 |
|
||||
|---|------|------|
|
||||
| D1 | **L1(생성-시 대화 ID 인자 주입) 전략 폐기** | 관리 모델 통일 우선. claude `--session-id`는 실측 확정된 레버지만, agent별 L1/L2 분기 유지 비용보다 단일 격리 메커니즘의 일관성을 우선함 (트레이드오프 인지 후 사용자 확정) |
|
||||
| D2 | **격리 식별자 = MAM 발급 isolation-UUID** (CLI 대화 ID와 분리) | cline 등 비-UUID 자체 ID 포맷 문제 원천 소멸 — CLI가 자기 방식대로 대화 ID를 mint하되 **자기만의 격리 디렉터리 안에서** 하게 함 |
|
||||
| D3 | **격리 정보를 세션 row(`isolation` 블록)로 영속화** | resume/resolve/stop이 단일 디스패치로 재적용 → 주입/해석 불일치(RK2) 차단 |
|
||||
| D4 | **claude 격리 레버 = `CLAUDE_CONFIG_DIR` + auth 시딩** | 실측: `~/.claude/` 한 지붕 아래 `.credentials.json`+`settings`+`plugins`+`projects/` 동거 확인. 대화만 옮기는 좁은 레버 부재 → 지붕 이동 + 시딩 계약 필수. ⚠️ 기존 문서의 `CLAUDE_PROJECT_DIR`은 **MAM resolver 읽기 전용 변수**(lib.sh:23,477)로 CLI **쓰기** 위치를 바꾸지 못함 — Rev.2의 해당 서술 정정 |
|
||||
| D5 | **cline 격리 레버 = `--data-dir` + `--config` 분리 조합** | 실측: `cline --data-dir <path>`("Use isolated local state", default `~/.cline`) + `--config <path>`(설정/auth, default `~/.cline/data/settings`) 별도 플래그 확인 → 대화만 격리·auth 공유 가능, 시딩 불필요 예상 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 배경 및 문제 정의
|
||||
|
||||
동일 CLI 계열(Claude/Cline)의 서로 다른 역할 에이전트가 같은 workspace에서 동시 구동될 때
|
||||
**동일한 대화 세션 ID를 공유**하는 결함 (`Problem_Definition.md`).
|
||||
|
||||
### 1.1 근본 원인 (코드 근거) 및 all-L2가 끊는 방식
|
||||
|
||||
| # | 원인 | 근거 | all-L2 해소 기전 |
|
||||
|---|------|------|------------------|
|
||||
| C1 | spawn 시 세션 ID 미지정 → CLI "cwd 최근 대화 상속" | `create_session.sh:125/:135` | 신규 격리 디렉터리엔 상속할 최근 대화가 **없음** → 각자 fresh 시작 |
|
||||
| C2 | 저장소가 workspace(cwd) 단위 키잉, role 차원 없음 | `lib.sh:480`, `:615` | 격리 디렉터리가 **UUID 네이밍** → cwd 파생 key 충돌 원천 소멸 |
|
||||
| C3 | resolver Tier-2가 mtime 최신 파일 반환 → 동일 UUID 해석 | `lib.sh:564` | 격리 디렉터리 안엔 대화가 **하나뿐** → disk-scan 항상 유일 후보, mtime 경합 소멸 |
|
||||
|
||||
### 1.2 불변 전제 (변경 금지)
|
||||
|
||||
- **cwd 공유**: 모든 에이전트는 `-c "$WORKSPACE"`로 동일 workspace에서 기동 (협업 전제). 격리는 **대화 상태 저장소의 위치만** env/플래그로 옮기며 cwd는 절대 건드리지 않음.
|
||||
- CLI(claude/cline/agy/hermes) 자체 미수정 — 인자/환경변수 인터페이스만 사용 (Non-Goal).
|
||||
- 기존 단일-에이전트 워크플로우 회귀 0.
|
||||
|
||||
---
|
||||
|
||||
## 2. 설계 (all-L2 단일 격리 메커니즘)
|
||||
|
||||
### 2.1 격리 디렉터리
|
||||
|
||||
- 생성 시 `uuidgen`으로 **isolation-UUID** 발급.
|
||||
- 격리 루트: `<workspace>/.mam/agent_homes/<isolation-uuid>/`
|
||||
- `.mam/` 하위 → `.gitignore:11` 자동 커버, `remove.sh`/stop 청소 계약에 자연 포함.
|
||||
|
||||
### 2.2 세션 row 스키마 확장 (`isolation` 블록)
|
||||
|
||||
```yaml
|
||||
tmux_sessions:
|
||||
- name: <session_name>
|
||||
role: <role>
|
||||
isolation:
|
||||
uuid: <isolation-uuid>
|
||||
root: .mam/agent_homes/<isolation-uuid>
|
||||
lever: claude_config_dir | cline_data_dir | home | <agy/hermes 프로브 결과>
|
||||
seeded: [".credentials.json", "settings.json", "plugins"] # 심링크 목록 (해당 시)
|
||||
```
|
||||
|
||||
- `atomic_dump_yaml` 경유로 DB+YAML 동시 기록 (P1 상시 미러 수정본 전제).
|
||||
- resume/resolve/stop은 이 블록만 읽는 **단일 디스패치 함수**로 재적용 — agent별 레버 차이는 이 함수 내부에 캡슐화.
|
||||
|
||||
### 2.3 agent별 레버 매핑 — ✅ Phase 0 실측 확정 매트릭스 (2026-07-10)
|
||||
|
||||
| Agent | Spawn 레버 | 시딩 목록 (전부 **심링크**) | 격리 내 대화 저장 실경로 | 실증 |
|
||||
|---|---|---|---|---|
|
||||
| claude | `CLAUDE_CONFIG_DIR=<root>` env | `.credentials.json`, `settings.json`, `plugins/` | `<root>/projects/<key>/<uuid>.jsonl` | ✅ 실호출 — jsonl 격리 생성, 로그인 유지, 실HOME 무변화(27→27) |
|
||||
| cline | `--data-dir <root>` 플래그 | `settings/*`(providers.json 등 5종), `globalState.json` | `<root>/sessions/<id>/<id>.json` ⚠️ | ✅ 실호출 — 세션 격리 생성, 실HOME 무변화(13→13) |
|
||||
| agy | `HOME=<root>` env | `~/.gemini/{oauth_creds.json, google_accounts.json, installation_id, settings.json, state.json}` + `antigravity-cli/{antigravity-oauth-token, installation_id, settings.json}` | `<root>/.gemini/antigravity-cli/conversations/<uuid>.db` | ✅ auth 검증(`agy models` — 시딩 전 실패/후 성공), fresh conversations/ 확인 |
|
||||
| hermes | `HOME=<root>` env | `~/.hermes/{auth.json, config.yaml, .env}` | `<root>/.hermes/state.db` (sessions 테이블) | ✅ 읽기 격리 검증 — 격리 HOME "No sessions found" + fresh state.db, 실HOME 세션 비노출 |
|
||||
|
||||
**Phase 0 실측 정정·주의사항**:
|
||||
1. ⚠️ **cline `--config` 가정 반증**: `--config ~/.cline/data/settings` 공유 지정만으로는 auth가 공유되지 않음(`Unauthorized`) — cline이 data-dir 안에 자체 settings를 생성. → **cline도 시딩 필수** (Rev.3 본문 "시딩 불필요 예상" 정정).
|
||||
2. ⚠️ **cline 격리 레이아웃 상이**: 격리 시 `<root>/sessions/`(실HOME은 `~/.cline/data/sessions/`) — resolver 재적용(T5)에서 **lever별 경로 템플릿 분기** 필요.
|
||||
3. hermes `config.yaml`에 실HOME 절대경로(런타임 `hermes-agent`) 내장 — 런타임은 읽기 공유라 무해하나, 격리 범위가 state/세션에 한정됨을 기록.
|
||||
4. agy는 첫 실행 시 격리 HOME에 디렉터리 구조를 자동 부트스트랩(fresh `conversations/` 포함).
|
||||
|
||||
- **resolver 연동**: 디스패치 함수가 row의 `isolation`을 읽어 `HOME_DIR`/`CLAUDE_PROJECT_DIR`(MAM 읽기 변수, `lib.sh:22-23`)를 격리 루트 기준으로 export한 뒤 `find_workspace_uuid`/resume 호출.
|
||||
|
||||
### 2.4 공통 불변식 (전략 무관 유지)
|
||||
|
||||
- **R1. claimed-set 필터**: Tier-2 반환 전, 같은 workspace의 다른 running row 소유 `*_own` 집합 제외 (`lib.sh:540-575`). 격리가 부분 실패해도 이중 배정 구조적 차단.
|
||||
- **R2. 생성-시 유일성 assert**: 새 `*_own`이 기존 running `*_own`과 충돌 시 `SystemExit` (`lib.sh:377` 근처).
|
||||
|
||||
---
|
||||
|
||||
## 3. 단계별 태스크
|
||||
|
||||
### Phase 0 — 검증 게이트 (**구현 전 필수·차단**, Rev.3 재조준: 구 G1 삭제)
|
||||
|
||||
- **G2-claude**: `CLAUDE_CONFIG_DIR=<격리경로>` 기동 시 (a) 대화 jsonl이 `<격리경로>/projects/<key>/`에 생성되는가 (b) `.credentials.json` **심링크만으로 로그인 유지**되는가 (c) settings/plugins 심링크로 행동 드리프트 없는가.
|
||||
- **G2-cline**: `--data-dir <격리경로> --config ~/.cline/data/settings` 기동 시 (a) 세션이 `<격리경로>/data/sessions/`(또는 상응 경로)에 격리 생성되는가 (b) auth/providers가 공유 config에서 정상 동작하는가.
|
||||
- **G2-agy**: `--new-project` per-role 부여 시 대화 격리 여부, 또는 데이터 경로 env 존재 여부. 부재 시 `HOME` 오버라이드+auth 시딩 유효성.
|
||||
- **G2-hermes**: home 이동 env/플래그 실측. 부재 시 `HOME` 오버라이드+auth 시딩 유효성.
|
||||
- **DoD**: `{agent × (레버, 시딩 목록, 대화 저장 실경로)}` 매트릭스 확정 → §2.3 갱신.
|
||||
|
||||
### Phase 1 — 공통 불변식 (Phase 0과 병렬 착수 가능)
|
||||
|
||||
- **T1. claimed-set 필터** / **T2. 생성-시 유일성 assert** (§2.4).
|
||||
- **DoD**: 동일 ID 강제 주입 2개 create → 두 번째 거부 (단위 재현).
|
||||
|
||||
### Phase 2 — all-L2 격리 구현 (구 Phase 2/3 통합)
|
||||
|
||||
- **T3. 격리 디렉터리 프로비저닝**: create 시 isolation-UUID 발급 → `.mam/agent_homes/<uuid>/` 생성 → agent별 시딩(§2.3, 심링크) 수행.
|
||||
- **T4. spawn 주입**: 디스패치 함수가 agent별 레버(env/플래그)로 격리 루트 주입.
|
||||
- **T5. 스키마 영속화 + 재적용**: `isolation` 블록 atomic_dump 기록, resume/resolve가 동일 디스패치로 재소싱 (**저장+재적용은 원자적 세트** — RK2).
|
||||
- **T6. stop 청소 계약**: `stop_session.sh`가 `isolation.root`를 퍼지(`rm -rf`), 심링크 대상 원본은 보존 확인.
|
||||
- **DoD**: 동일 workspace, 같은 CLI 2개(다른 role) 동시 생성 → 대화 파일 물리 분리, `*_own` 상이, 교차 write 0.
|
||||
|
||||
### Phase 3 — 통합 및 회귀 검증
|
||||
|
||||
- **V1**: planner/reviewer-a(claude) + developer/reviewer-b(cline) 4개 동시 기동 → 4개 대화 ID 전부 유일.
|
||||
- **V2**: 동시 write 락 충돌·컨텍스트 오염 재현 불가.
|
||||
- **V3**: 각 role resume이 자기 대화만 복원 (isolation 재적용 경유).
|
||||
- **V4**: 단일-에이전트 기존 워크플로우 회귀 0 (격리 미사용 경로 불변).
|
||||
- **V5**: stop 후 격리 저장소 잔존 0 + 실HOME auth/설정 원본 무손상.
|
||||
|
||||
---
|
||||
|
||||
## 4. 리스크 및 검수 포인트 (Rev.3 갱신)
|
||||
|
||||
| ID | 리스크 | 완화 |
|
||||
|----|--------|------|
|
||||
| RK1 | 격리 실패/부분 적용 시 이중 배정 | R1 claimed-set 필터가 최후 방어선 (무조건 유지) |
|
||||
| RK2 | spawn 주입 경로와 resolve/resume 스캔 경로 불일치 → 전역 회귀 | T5 "저장+재적용" 원자적 세트, 단일 디스패치 함수 강제 |
|
||||
| RK3 | **시딩 드리프트**: CLI 업데이트로 신규 파일 등장 시 심링크 목록 누락 → 행동 이상 | `seeded` 목록을 row에 기록, Phase 0 매트릭스에 파일 목록 명세, 온보딩 문서화 |
|
||||
| RK4 | 토큰 갱신 발산 (복사 시딩 시) | **심링크 강제** — 갱신이 원본 단일 파일에 수렴 (현행 다중 인스턴스 동작과 동일) |
|
||||
| RK5 | 비정상 종료 시 격리 디렉터리 누수 | `.mam/` 하위 배치로 remove.sh 전체 청소 커버 + T6 stop 퍼지 + (선택) create 시 고아 `agent_homes/*` GC |
|
||||
| RK6 | 단일-에이전트 기존 사용자 회귀 | 격리 발동을 명시 플래그/다중성 조건으로 제어 (`--isolate` 등, Phase 0 후 확정), V4 회귀 게이트 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 승인 및 다음 단계
|
||||
|
||||
- 본 계획(Rev.3)은 **Phase 0 게이트 통과 전 코드 구현 착수 금지**를 대전제로 유지한다.
|
||||
- 다음 액션: **Phase 0 (G2-claude / G2-cline / G2-agy / G2-hermes) 프로브 실행** — 스크래치 워크스페이스에서 실측 후 §2.3 매트릭스 확정.
|
||||
@@ -0,0 +1,132 @@
|
||||
# 🛠️ 세션 ID 중복 충돌 해결 종합 설계 및 구현 계획서 (Rev.3 — 단일 격리 디렉터리 통합본)
|
||||
|
||||
동일 CLI 계열(Claude / Cline)의 서로 다른 역할 에이전트가 같은 workspace에서 동시 구동될 때 대화 세션 ID를 공유하는 결함([Problem_Definition.md](Problem_Definition.md))을 해결하기 위한 최종 종합 설계안 및 구현 계획입니다.
|
||||
|
||||
기존의 하이브리드 분기(L1/L2 병행) 구조를 걷어내고, **"모든 에이전트의 격리 디렉터리 관리 일원화"**라는 사용자(GM) 피드백을 반영하여 설계를 단순화한 버전입니다. Rev.3에서는 **실측 프로브 결과에 따른 격리 레버 정정 및 auth 시딩 계약**(사용자 승인 조건)을 반영했습니다. 상세 계획의 단일 원본은 [implementation_plan.session_isolation.md](implementation_plan.session_isolation.md) (Rev.3)입니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 배경 및 문제 정의
|
||||
|
||||
동일한 워크스페이스에서 다중 역할 에이전트(예: `planner`와 `reviewer-a`, `developer`와 `reviewer-b`)가 기동될 때, 동일한 대화 UUID 또는 Cline 대화 ID를 공유함으로써 컨텍스트가 오염되고, 히스토리 쓰기 경합으로 인한 락 충돌 및 데이터 유실이 발생하는 문제가 발생했습니다.
|
||||
|
||||
### 1.1 근본 원인 분석
|
||||
* **C1. 생성 시 고유 ID 미지정**: 세션 생성 시점에 특정 세션 ID 인자를 지정하지 않아 CLI 기본 동작인 "최근 대화 상속"이 실행됨.
|
||||
* **C2. 워크스페이스 단위 키잉**: 대화 세션 매핑이 역할(role) 차원 없이 단순히 `workspace_root` 경로만을 키로 삼아 이뤄짐.
|
||||
* **C3. mtime 기반 추측 바인딩 (Tier-2)**: resolver가 워크스페이스 내에서 최종 수정 시간(mtime)이 가장 최신인 세션을 바인딩하여, 다른 역할의 에이전트가 동일한 UUID를 상속받게 됨.
|
||||
|
||||
---
|
||||
|
||||
## 2. 개정된 설계 방향: "단일 격리 디렉터리" 일원화 (Rev.3 정정 반영)
|
||||
|
||||
각 에이전트의 ID 파라미터 지원 여부에 따라 구현을 분기하는 대신, **모든 에이전트에 대해 균일하게 격리 디렉터리 주입 방식으로 일원화**하여 아키텍처의 복잡도를 제거합니다.
|
||||
|
||||
> ⚠️ **Rev.3 정정 (실측 근거)**: 이전 판의 "Claude = `CLAUDE_PROJECT_DIR` 격리"는 **동작하지 않는 설계**였습니다. `CLAUDE_PROJECT_DIR`은 MAM resolver의 **읽기 전용** 변수(`lib.sh:23,477`)로, claude CLI가 대화를 **쓰는** 위치를 바꾸지 못합니다. claude의 쓰기 위치 이동은 `CLAUDE_CONFIG_DIR`(`~/.claude` 지붕 전체 이동)로만 가능하며, 이 경우 auth/설정 시딩이 필수입니다(§2.3). 또한 cline은 실측 결과 per-session `HOME`이 아닌 **전용 `--data-dir`/`--config` 분리 플래그**를 보유해 시딩 없이 격리 가능합니다.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[세션 생성] --> U[uuidgen: isolation-UUID 발급]
|
||||
U --> B[.mam/agent_homes/<uuid>/ 생성]
|
||||
B -->|Claude| B1[CLAUDE_CONFIG_DIR 주입 + auth/설정 심링크 시딩]
|
||||
B -->|Cline| B2[--data-dir 격리 + --config 공유 auth]
|
||||
B -->|Agy / Hermes| B3[Phase 0 프로브: 전용 레버 or HOME+시딩 폴백]
|
||||
A --> C[Defense-in-depth: R1/R2 resolver 불변식]
|
||||
B1 & B2 & B3 --> E[isolation 블록 세션 row 영속화 → resume/resolve/stop 재적용]
|
||||
```
|
||||
|
||||
### 2.1 일원화 설계의 핵심
|
||||
* **격리 식별자 ≠ 대화 식별자**: MAM이 `uuidgen`으로 발급하는 **isolation-UUID는 디렉터리 식별자**입니다. CLI는 자기 방식대로 대화 ID를 mint하되(claude UUID, cline `epoch_rand` 등) **자기만의 격리 디렉터리 안에서** 하게 됩니다 — cline의 비-UUID 포맷 문제가 원천 소멸합니다.
|
||||
* **작업 디렉터리(Cwd) 공유**: 에이전트들의 작업 디렉터리는 기존과 동일하게 같은 프로젝트 루트를 바라봅니다(`-c "$WORKSPACE"` 불변). 협업 소스코드 컨텍스트는 완벽히 일치하며, 격리는 **대화 상태 저장소의 위치만** 이동합니다.
|
||||
* **격리 루트**: `<workspace>/.mam/agent_homes/<isolation-uuid>/` — `.gitignore`(`.mam/`) 자동 커버, remove/stop 청소 계약에 자연 포함.
|
||||
* **스키마 영속화**: 세션 row에 `isolation: {uuid, root, lever, seeded[]}` 블록을 `atomic_dump_yaml`로 영속화(DB+YAML). resume/resolve/stop은 이 블록만 읽는 **단일 디스패치 함수**를 경유 — agent별 레버 차이는 함수 내부에 캡슐화되어 관리 모델은 완전 통일됩니다.
|
||||
* **근본 원인 해소 기전**: 신규 격리 디렉터리엔 상속할 최근 대화가 없음(C1 무해화) / UUID 네이밍으로 cwd-key 충돌 소멸(C2) / 디렉터리당 대화 1개 → resolver 항상 유일 후보(C3 소멸).
|
||||
|
||||
### 2.2 agent별 격리 레버 매핑 — ✅ Phase 0 실측 확정 (2026-07-10)
|
||||
|
||||
| Agent | Spawn 레버 | 시딩 (전부 **심링크**) | 격리 내 대화 경로 | 실증 |
|
||||
|---|---|---|---|---|
|
||||
| claude | `CLAUDE_CONFIG_DIR=<root>` env | `.credentials.json`, `settings.json`, `plugins/` | `<root>/projects/<key>/<uuid>.jsonl` | ✅ 실호출 PASS |
|
||||
| cline | `--data-dir <root>` 플래그 | `settings/*` + `globalState.json` (⚠️ `--config` 공유만으론 auth 미공유 — 실측 반증, 시딩 필수) | `<root>/sessions/<id>/<id>.json` (⚠️ 실HOME `data/sessions/`와 레이아웃 상이) | ✅ 실호출 PASS |
|
||||
| agy | `HOME=<root>` env | `~/.gemini/` auth 3종(`oauth_creds.json`, `google_accounts.json`, `antigravity-oauth-token`) + 메타(`installation_id`/`settings.json`/`state.json`) | `<root>/.gemini/antigravity-cli/conversations/<uuid>.db` | ✅ auth 검증 PASS (시딩 전 실패→후 성공) |
|
||||
| hermes | `HOME=<root>` env | `~/.hermes/{auth.json, config.yaml, .env}` | `<root>/.hermes/state.db` | ✅ 읽기 격리 PASS ("No sessions found" + fresh state.db) |
|
||||
|
||||
### 2.3 시딩 계약 (claude 및 HOME 폴백 agent) — 사용자 승인 조건
|
||||
* **심링크 강제, 복사 금지**: 복사 시 토큰 갱신이 격리 사본으로 발산해 원본과 어긋남. 심링크는 갱신이 원본 단일 파일에 수렴(현행 다중 인스턴스 동작과 동일 의미론).
|
||||
* claude 시딩 목록(초안): `.credentials.json`, `settings.json`, `plugins/` — Phase 0에서 최종 확정, row의 `seeded[]`에 기록.
|
||||
* stop 퍼지 시 **심링크 원본 무손상** 검증 포함.
|
||||
|
||||
### 2.4 R1/R2 resolver 불변식 (2중 안전 장치)
|
||||
* **R1**: resolver(`find_workspace_uuid` 등)가 최신 파일을 스캔해오기 전, 현재 실행 중인 다른 세션들이 소유한 `*_own` 대화 ID 집합을 후보군에서 제외(claimed-set filtering)합니다.
|
||||
* **R2**: `atomic_dump` 시점에 새로 등록하려는 세션 ID가 이미 실행 중인 다른 세션의 ID와 중복될 경우 `SystemExit` 에러로 강제 진입 차단합니다.
|
||||
|
||||
### 2.5 정리(Cleanup) 계약 (RC-2)
|
||||
* 세션 정지(`stop_session.sh`) 시 `isolation.root`를 일괄 청소(`rm -rf`)하는 단순·명확한 클린업 규칙. `.mam/` 하위 배치로 `remove.sh` 전체 청소도 자동 커버.
|
||||
|
||||
### 2.6 Non-Goals
|
||||
* 에이전트 CLI(`claude`, `cline`, `agy`, `hermes`) 자체 바이너리/코드를 수정하지 않습니다. 구동 시 외부 환경변수·플래그 주입 인터페이스만 사용합니다.
|
||||
* 기존 단일 에이전트 동작 구조의 하위 호환성은 완벽하게 보존합니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 단계별 구현 계획 (Roadmap)
|
||||
|
||||
**대전제: Phase 0 검증 게이트 통과 전에는 격리 주입(Phase 2 이후) 코드 구현에 착수하지 않습니다.**
|
||||
|
||||
```
|
||||
Phase 0 (격리 레버 실측 및 검증 — G2 재조준)
|
||||
▼
|
||||
Phase 1 (R1/R2 공통 불변식 필터 — Phase 0 산출물 비의존, 병렬 선행 가능)
|
||||
▼
|
||||
Phase 2 (격리 프로비저닝·시딩·주입 및 isolation 스키마 영속화 구현)
|
||||
▼
|
||||
Phase 3 (stop_session.sh 클린업 계약 연동 구현)
|
||||
▼
|
||||
Phase 4 (통합 및 회귀 검증)
|
||||
```
|
||||
|
||||
### Phase 0 — 격리 레버 실측 (구현 전 필수 실측)
|
||||
* **G2-claude**: `CLAUDE_CONFIG_DIR=<격리경로>` 기동 시 (a) 대화 jsonl이 `<격리경로>/projects/<key>/`에 생성 (b) `.credentials.json` **심링크만으로 로그인 유지** (c) settings/plugins 심링크로 행동 드리프트 없음.
|
||||
* **G2-cline**: `--data-dir <격리경로> --config ~/.cline/data/settings` 기동 시 (a) 세션이 격리경로에 생성 (b) 공유 auth 정상 동작.
|
||||
* **G2-agy / G2-hermes**: 전용 레버(project/home env) 실측, 부재 시 `HOME` 오버라이드+auth 시딩 유효성.
|
||||
* **DoD**: `{agent × (레버, 시딩 목록, 대화 저장 실경로)}` 매트릭스 확정 → §2.2 갱신.
|
||||
|
||||
### Phase 1 — 공통 불변식 구현 (전략 무관, 선행 가능)
|
||||
* *의존성 참고*: Phase 1은 격리 프로브 결과에 의존하지 않고 공통 `lib.sh`에만 적용되므로, **Phase 0 완료 여부와 무관하게 병렬로 또는 선제적으로 구현할 수 있습니다.**
|
||||
* **T1. claimed-set 필터 구현**: `lib.sh` (`find_workspace_uuid` 계열) 탐색 로직 수정. 후보군 중 다른 실행 중인 row의 `*_own`을 필터링 아웃.
|
||||
* **T2. 생성-시 중복 assertion**: 세션 등록/덤프 로직 부근에서 중복 assert — 중복 ID 충돌 시 즉시 거부.
|
||||
* **DoD**: 동일 대화 ID 강제 주입으로 세션 2개 생성 시도 시, 두 번째 생성 요청이 거부됨을 증명.
|
||||
|
||||
### Phase 2 — 격리 프로비저닝 및 영속화 구현 (전체 에이전트 적용)
|
||||
* **T3. 격리 프로비저닝**: create 시 isolation-UUID 발급 → `.mam/agent_homes/<uuid>/` 생성 → agent별 심링크 시딩(§2.3).
|
||||
* **T4. spawn 주입**: 디스패치 함수가 agent별 레버(§2.2: `CLAUDE_CONFIG_DIR` / `--data-dir` / 프로브 결과)로 격리 루트 주입.
|
||||
* **T5. 스키마 영속화**: `isolation` 블록을 row에 저장하고 resume/resolve 시 재소싱 적용 — **저장+재적용은 원자적 세트**.
|
||||
* **DoD**: Claude / Cline 세션 각각 2개 동시 생성 시 대화 파일 물리 분리·캐시 비공유, resume 시 올바른 복원 확인.
|
||||
|
||||
### Phase 3 — stop 정리 계약 확장
|
||||
* **T6. stop 정리 계약 확장**: `stop_session.sh`가 `isolation.root`를 자동 퍼지(`rm -rf`), **심링크 원본 무손상 검증** 포함.
|
||||
* **DoD**: stop 후 격리 디렉터리 잔존 0, 실HOME auth/설정 원본 무손상, 디스크 누수 없음.
|
||||
|
||||
### Phase 4 — 통합 및 회귀 검증
|
||||
* **V1. 다중 기동 테스트**: planner(claude), reviewer-a(claude), developer(cline), reviewer-b(cline) 4개 동시 기동 시 4개 세션 ID 모두 유일성 확보 검증.
|
||||
* **V2. 동시 쓰기 경합**: 4개 에이전트 동시 동작 시 락 경합/데이터 유실 현상 재현 불가 확인.
|
||||
* **V3. 단일 세션 회귀 검증**: 격리 정책 적용 후 기존 단일 에이전트 구동 환경에서 문제없이 정상 동작함을 검증.
|
||||
|
||||
---
|
||||
|
||||
## 4. 리스크 및 검수 포인트 (Reviewer 관점, Rev.3 갱신)
|
||||
|
||||
| ID | 리스크 | 완화책 |
|
||||
|----|--------|------|
|
||||
| **RK1** | 격리 경로 주입 후 resolve/resume 시 전역 기본 경로 스캔으로 회귀 | `isolation` 블록 저장과 resume 시 재적용을 원자적 세트로 묶고 단일 디스패치 함수 강제 |
|
||||
| **RK2** | **시딩 드리프트**: CLI 업데이트로 신규 파일 등장 시 심링크 목록 누락 → 격리 인스턴스 행동 이상 | `seeded[]`를 row에 기록, Phase 0 매트릭스에 시딩 파일 목록 명세 |
|
||||
| **RK3** | **토큰 갱신 발산**: auth 파일을 복사 시딩하면 격리 사본의 토큰 갱신이 원본과 어긋남 | **심링크 강제** — 갱신이 원본 단일 파일에 수렴 |
|
||||
| **RK4** | 비정상 종료 시 격리 디렉터리 미정리로 인한 디스크 누수 | `.mam/` 하위 배치(remove.sh 커버) + stop 퍼지 + 고아 `agent_homes/*` GC(선택) |
|
||||
| **RK5** | 단일 에이전트 워크플로우 기존 사용자의 하위 호환성 회귀 | 격리 활성화를 세션 다중성 조건 혹은 명시적 플래그(`--isolate-strict`)로 제어, V3 회귀 게이트 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 의사결정 및 다음 단계
|
||||
|
||||
* ✅ 모든 에이전트를 격리 디렉터리 방식으로 일원화하는 방향 최종 승인 (트레이드오프 — claude `--session-id` 실측 확정 레버의 미채택 — 인지 후 결정).
|
||||
* ✅ 승인 조건 반영: (1) Phase 0에 claude `CLAUDE_CONFIG_DIR`+심링크 로그인 유지 프로브 포함, (2) 시딩 계약(§2.3) 명문화.
|
||||
* ⏭️ 승인에 따라 **Phase 0 (격리 레버 실측)** 및 **Phase 1 (공통 불변식 필터)** 태스크에 착수합니다. Phase 2 이후 구현은 Phase 0 매트릭스 확정 후 진행합니다.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Task Checklist — 배포 스크립트 URL 파라미터화 (Rev.1)
|
||||
|
||||
> 기준 문서: [implementation_plan.md](implementation_plan.md) (Rev.1)
|
||||
> 담당: Developer Agent | 순서대로 수행하며 완료 시 `[x]` 갱신
|
||||
|
||||
## Phase 1 — 코드 수정
|
||||
|
||||
- [ ] **T1. `deploy/install.sh` 파라미터화** (§3.1)
|
||||
- 57행: `REPO_URL="${MAM_REPO_URL:-https://git.godopu.com/tmpl/multi-agent-mux.git}"`
|
||||
- 58행: `ARCHIVE_URL="${MAM_ARCHIVE_URL:-https://git.godopu.com/tmpl/multi-agent-mux/archive/main.tar.gz}"`
|
||||
- [ ] **T2. `deploy/update.sh` 파라미터화** (§3.2)
|
||||
- 138행: `INSTALLER_URL="${MAM_INSTALLER_URL:-https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh}"`
|
||||
- 체이닝 상속 계약(접두 대입 → 자식 bash 상속) 주석 1줄 추가
|
||||
|
||||
## Phase 2 — 문서화
|
||||
|
||||
- [ ] **T3. `.env.example`에 `# deploy / distribution source` 섹션 추가** (§3.3)
|
||||
- `MAM_REPO_URL` / `MAM_ARCHIVE_URL` / `MAM_INSTALLER_URL` 3종, 기존 `#default:` 서식 준수
|
||||
- "deploy 스크립트는 `.env`를 파싱하지 않음 — export/접두 대입으로 전달" 주의 문구 포함
|
||||
- 미러 운영 시 3변수 동시 설정 권고 문구 포함 (§3.5)
|
||||
- [ ] **T4. `deploy/README.md`에 미러/포크 설치·업데이트 예시 추가** (§3.6)
|
||||
- 파이프 실행 시 접두 대입을 `bash` 쪽에 붙이는 예시 포함
|
||||
|
||||
## Phase 3 — 검증 (plan §5, DoD)
|
||||
|
||||
- [ ] **V1.** `bash -n deploy/install.sh deploy/update.sh` 통과
|
||||
- [ ] **V2.** `shellcheck deploy/install.sh deploy/update.sh` 신규 경고 0
|
||||
- [ ] **V3.** 기본값 3개가 변경 전 하드코딩 문자열과 byte-identical (grep 대조)
|
||||
- [ ] **V4.** 스크래치 디렉터리에서 `MAM_ARCHIVE_URL` 오버라이드가 fetch에 반영됨 확인
|
||||
- [ ] **V5.** `MAM_INSTALLER_URL` 오버라이드 해석값 확인 (실 워크스페이스 파괴적 실행 금지)
|
||||
- [ ] **V6.** 리포 루트 재실행 회귀: fetch 생략 경로 정상 동작
|
||||
- [ ] **V7.** 문서(.env.example / deploy/README.md)-코드 간 변수명 철자 교차 대조
|
||||
|
||||
## Phase 4 — 마감
|
||||
|
||||
- [ ] **T5.** 단일 원자적 커밋: `feat(deploy): parameterize distribution URLs via MAM_*_URL env vars`
|
||||
- [ ] **T6.** Reviewer A / Reviewer B에 변경 범위 통지 및 이중 리뷰 요청
|
||||
- [ ] **T7.** 양측 PASS 확인 후 세션 종료 (`multi-agent-mux-stop`) / NOT PASS 시 Planner로 환류
|
||||
|
||||
agy --conversation=20cc2d8e-49f1-4a83-96b5-c49d320b42af
|
||||
Reference in New Issue
Block a user