Files
multi-agent-mux/implementation_plan.session_isolation.md
T

11 KiB

Implementation Plan — 세션 ID 중복 충돌 해소 / 역할별 세션 격리 (Rev.3)

  • 작성자: Planner Agent
  • 날짜: 2026-07-10 (Rev.2 → Rev.3 개정)
  • 상태: Draft (Phase 0 검증 게이트 대기 — 구현 미착수)
  • 관련 자료: Problem_Definition.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_DIRMAM 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 블록)

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.shisolation.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 매트릭스 확정.