15.9 KB · 수정 2026-06-03 11:14
목차

협의 결과 — (다) CLI 러너 설계 확정 (hub #28, 2026-06-01)

hub session #28 (2026-06-01, 종료=합의). 채티(PLANNER)↔GPT(gpt-5.5) 협의로 SARA→코디 위임 (다) CLI 러너 설계 확정. 이 페이지는 §11(#25 codi 인식 재설계)의 후속이며, (다) 코디 지시문(.md) 작성의 직접 입력이다. 편집 원칙: 확정 결론 위주. 협의 중 폐기·철회된 채티 사전 추측은 본문에서 삭제하고, 정정된 최종안만 수록.

목차

  1. 개요
  2. 핵심 합의 (확정)
  3. 확정 설계 — Q1~Q7
  4. 코디 지시문(.md) 골격 (확정)
  5. .md 발행 전 선결 확인 (채티 직접)
  6. 메타

1. 개요

2. 핵심 합의 (확정)

GPT가 §실코드를 읽고 채티 사전안 중 3건을 정정, 채티 전부 수용. 나머지는 채티·GPT 일치. 정정·확정 3건 1. 권한 모델 정정: --permission-mode acceptEdits는 위험작업 차단자가 아니다(Claude Code 권한 프롬프트 정책일 뿐). 실제 차단 주체 = .claude/settings.json deny/hook + broker(:7777). acceptEdits와 broker는 충돌이 아니라 직렬 방어층. → 코디 지시문 완료보고에 "broker 우회 0건"을 evidence로 명시. 2. push/tests 권위화: cmdboard _extract_codi_result_structured는 현재 push·tests를 텍스트 regex로 뽑음(코디 자기보고 의존). → "그대로 이식" 폐기. runner가 직접 실행/검증: push = git ls-remote로 upstream sha 비교, tests = runner 화이트리스트 명령(python -m pytest 등) 직접 실행. 코디가 "push/통과"라 써도 runner 미검증이면 pushed=false|unknown, tests[].source="codi_report_untrusted" 또는 [] → EVALUATOR fail. 3. 롤백 한계 명시: codi_snapshot.py는 untracked 파일 목록만 저장(내용 미보존). → "완전 롤백" 근거 부족. snapshot 확장은 별 PR 분리, 본 작업은 계약에 rollback.capability="partial_only" 표기로 우선 봉쇄. 일치(확정): Q1 이식 경계·MCP 시그니처 / Q2-b broker 발화 전제→PROBE 실측 검증 / Q3-② 누락 경로 5개→finalize_contract() 경유 / Q4 cmdboard에 명시 ResultContract 클래스 없음activity_logs.payload+HandoffArtifact(codi_result) 정합, 버전 문자열 sara.codi_cli_result.v1+upstream.commit / Q5 codi_bridge.py가 (가) Agent 경로로 이미 결합→게이트 분기, vendored router_evaluator.py 직접 수정 금지 / Q6·Q7 PROBE P-0~P-5(+P-6 머지).

3. 확정 설계 — Q1~Q7

Q1. 이식 경계 + MCP 도구 시그니처

그대로 이식(vendored): claude -p subprocess 실행 패턴(stdin 프롬프트·cwd=repo·argv 방식·shell injection 회피) / stream-json 파싱·사용량 추출(_parse_stream_json·_extract_token_usage) / stall·timeout 감시(_drain_with_stall_watchdog, 단 NDJSON tee 추가) / 실패 분류(_classify_failure) / pre-run snapshot(create_pre_run_snapshot·collect_post_run_summary, 단 untracked 내용 보존 확장) / 민감값 scrub. 버림: cmdboard 분산 claim 큐(claim_next_codi_request) / pending_external 폴링 / apply_codi_result 직접 호출 / add_codi_progress 강결합 / task_code 필수 전제(SARA는 run_id가 1차키, task_code/task_id 선택). 신규: sara/codi_cli_runner.py(vendored 핵심, 상단 upstream hash) / codi_run SDK MCP 도구(create_sdk_mcp_server 정합) / ResultContract 직렬화기(성공·실패·timeout·stall·crash 동일 스키마) / NDJSON transcript writer(logs/codi_runs/<run_id>.ndjson, RDS는 pointer만) / git authority collector. 도구 시그니처:

tool: codi_run
input: { instructions_md:str, repo_cwd:str, model:str|null,
         effort:"low|medium|high|xhigh"|null, fallback_model:str|null,
         max_turns:int, timeout_s:int, stall_s:int,
         task_id:int|null, task_code:str|null, run_label:str|null }
output: { ok:bool, result_contract:ResultContract }

검증: instructions_md="OK만 보고"+scratch repo → 스키마 필드 누락 0. repo_cwd 미존재 → ok=false, status="fail", failure.error_code="repo_path_missing", transcript 존재.

Q2. claude -p 실행 + 권한 모델

실행 인자: cmdboard 현행 claude -p --output-format stream-json --verbose --max-turns N --permission-mode <mode> + SARA 신규 확장 --model / --effort / --fallback-model(§5에서 정확 표기 확정 후 사용). - (a) acceptEdits ↔ broker = 충돌 아님, 직렬 방어층. 위험작업 실차단 = broker 단독(PreToolUse 훅이 Bash/Write/Edit/MultiEdit/NotebookEdit 가로채 분류·차단). - (b) broker 훅이 claude -p 내부 Bash/Write에서 발화하는가 = 전제 채택(Notion 인수인계서 실측 기록 근거), 단 구현 완료 조건 = PROBE 실측. broker 요청 0건이면 SARA_CODI_CLI 플립 금지. - (c) --dangerously-skip-permissions 우회 방지: argv builder = allowlist(사용자 CLI 인자 문자열 주입 차단, instructions_md는 stdin 전용) / permission_mode에 "dangerously" 포함 시 acceptEdits 강제 치환 / transcript에 argv_safe 기록 / 단위테스트 assert "--dangerously-skip-permissions" not in argv_safe.

Q3. 보완 5종 — 평가·확장

① 사실 출처 = git/RDS: _extract_codi_result_structuredchanged_files·commit_sha·branch는 재사용, pushed·tests는 regex 의존 → 확장. collect_post_run_summary 확장(branch/head before·after, commit_hashes, dirty_after, upstream_ref, remote_sha, pushed) + runner가 테스트 직접 실행(allowlist python -m pytest|unittest 등 → {cmd,exit_code,passed,duration_ms,source="runner"}). ② 종단 계약 항상 발행: 누락/취약 경로 5개(task_code 즉시 return·최상위 예외·activity log best-effort·subprocess 예외 흡수·transcript pointer 비필수). → 시작 시 빈 ResultContract 선생성 + 모든 return은 finalize_contract() 경유 + 최상위 try/except(crash)/finally(repo 상태·transcript·persist). 검증: repo missing / claude_path 없음 / spawn RuntimeError mock / stall mock 각각 계약 발행. ④ 스냅샷 재개/롤백: 현행 충분(status_porcelain/full·diff_stat·worktree.patch·staged.patch·untracked_files·meta·head/branch). 부족 = untracked 파일 내용 미저장 → 완전 롤백 불가. 재개 vs 롤백 결정표: commit 0+clean=기록만 / commit 0+dirty+push X=자동 롤백 금지·승인 후 정리 / commit≥1+push X=재개 우선·롤백은 승인 / commit≥1+push O=자동 롤백 금지 / snapshot 실패=시작 금지 / untracked 내용 있음=rollback.capability="partial_only". ⑤ NDJSON + stall watchdog: _drain_with_stall_watchdog 재사용+확장(stdout line 즉시 파일 append, stderr 별도, last_event_at/bytes/sha256/line_count). 영속화 = 파일 logs/codi_runs/<run_id>.ndjson, RDS엔 path·bytes·sha256·last_event_at만(SARA DDL 0).

Q4. ResultContract 스키마 (항상 발행)

cmdboard에 명시 ResultContract 클래스 없음 → 정합 대상 = activity_logs.payload + HandoffArtifact(codi_result). 최상위 키: contract_version("sara.codi_cli_result.v1"), upstream{repo,ref,commit,files}, run{run_id,task_id,task_code,started/ended_at,duration_ms,status:pass|fail|timeout|stall|crash|blocked|partial,ok,stage}, invocation{argv_safe,cwd,model,effort,fallback_model,max_turns,permission_mode,dangerous_skip_permissions:false}, repo{branch/head before·after,dirty before·after,upstream_ref}, evidence{commits,commit_count,changed_files,push{pushed,remote_sha,method},tests[],git_status_after}, evaluator{verdict:pass|reject|not_run,reason,gaps,action}, failure{error_code,message,classification,retryable}, snapshot{snapshot_id,dir,head_before,dirty,rollback_capability:none|full|partial_only|manual_required,warnings}, transcript{ndjson_path,stderr_path,bytes,sha256,line_count,last_event_at,stdout_empty}, usage{...,usage_status:known|unknown}, handoff{activity_log_id,artifact_id,artifact_type:"codi_result",persisted,persist_error}. 규칙: 필드 부재 금지(모르면 null·빈목록 []·미실행 "not_run"). 코디 자유서술은 summary_untrusted로만 별도 저장, evidence로 안 씀.

Q5. EVALUATOR/ROUTER 결합

현황: router_evaluator.py = vendored copy(UPSTREAM_COMMIT="02b78ed"), evaluate_completion(result) 규칙 기반. codi_bridge.py는 이미 (가) mcp__claude-code__Agent 경로(_delegate_and_verify)로 결합. 배선: stream_route() 유지 → route=task|verify_required AND SARA_CODI_CLI=1이면 Agent 위임 대신 run_codi_cli_contract() 호출 → contract.evidenceevaluate_completion 입력으로 어댑트. vendored router_evaluator.py 직접 수정 금지, wrapper에서 정책 강제: contract_requires_commit && commit_count==0 → reject("no_verified_commit") / no_runner_evidence → reject("no_evidence") / else evaluate_completion. 외부 /chat 응답 형태 불변, ResultContract 전체는 SSE 미노출, 저장은 activity_logs.payload(+가능시 HandoffArtifact), SARA DDL 0. 검증: 일반질문→codi_run 0·기존 응답 동일 / 코드작업→codi_run 1 / 가짜 커밋→commit_count=0→reject / activity_logs에 sara_bridge_route·sara_bridge_task_verdict·codi_cli_result.

Q6. 코디 지시문(.md) 합성 + 표준 템플릿

관계: .md = 채티/사용자 작성 작업 본문, build_codi_prompt = runner가 붙이는 실행 envelope, ResultContract = runner가 git/테스트/전사로 채우는 권위 결과. stdin 합성 = [envelope: 역할/권한/금지/결과계약] --- [.md 원문] --- [tail: 보고형식 + 자기보고는 참고용 명시]. 표준 .md = 목적 / 범위(수정 허용·금지 경로) / 금지(dangerous-skip·force-push·reset --hard·rm -rf·AWS 삭제·DB DROP·운영배포·대량 리팩터·시크릿 출력) / 진행 단계(branch·head·status 확인→최소 수정→허용 테스트→커밋·push는 승인 시만→보고) / 검증 기준(명령·기대 exit_code 0·범위 내 변경) / 완료 보고 형식(RESULT_SUMMARY·CHANGED_FILES·TESTS·COMMIT·PUSHED — runner가 git 재검증) / 롤백(자동 안 함, 승인 요청) / 성공 기준(status=pass·verdict=pass·commit_count≥1·필수 테스트 exit 0·broker 우회 0).

Q7. PROBE 재설계 (확정)

전제: (다)는 서브에이전트 디스패치가 없으므로 Agent type 'codi' not found는 경로상 소멸. 검증 포인트 = "codi 인식"이 아니라 "claude -p 직접 실행 + broker/hook/evidence 작동". - P-0 인식 불필요 확인: scratch repo + "OK_CLI_DIRECT만 출력" → exit 0, transcript 존재, Agent type 'codi' not found 0건, argv에 mcp serve/Agent/subagent_type 없음. - P-1 broker 발화 실측: "Bash로 git status --short" → broker PreToolUse ≥1. 0건이면 플립 금지. - P-2 Write/Edit broker 실측: scratch에 무해 파일 생성 → broker 로그 ≥1. 0건이면 자동쓰기 금지. - P-3 force-push 게이트: dry-run/로컬 bare 대상 git push --force-with-lease --dry-run → broker 위험분류·텔레그램 경로, 실 remote 변경 0. - P-4 실커밋 1 + pass: 파일 1 수정·테스트 1 성공·커밋 1·push 없음 → commit_count=1, changed_files 포함, tests[0].exit_code=0, push.pushed=false, evaluator.verdict=pass. - P-5 실패 경로 계약 보장: timeout/stall/crash mock → status 해당값, 필드 누락 0, transcript pointer·repo 상태 포함. (§4-② 충족 증거, 필수 포함.) - P-6 master 머지/플립: P-0~P-5 통과 + 별도 사용자 승인 + SARA_CODI_CLI=1, 실패 시 =0 즉시 롤백. - fail-safe: P-1·P-2·P-3 중 한 단계라도 broker 요청 0건 = 플립 영구 차단(자동 재시도 금지, 사용자 수동 확인).

4. 코디 지시문(.md) 골격 (확정)

GPT 골격 채택 + 채티 보강. (다) 구현 지시문은 아래 골격으로 작성한다. - 목적: SARA가 코드/셸/파일을 직접 안 하고 별도 claude -p에 위임하는 CLI runner 구현. cmdboard codi_runner_cli 패턴 vendored 이식 + ResultContract/NDJSON/stall/evaluator 보장. - 범위: SARA repo(C:\dev\SARA)만 수정. cmdboard는 읽기 참조만. SARA DDL 0. cmdboard 직접 import 금지. vendored 파일 상단에 # upstream: delix0731/cmdboard@<ref>:<commit_sha> :: <path> 1줄 강제(부팅 시 hash 검증 실패→러너 시작 거부). - 금지: (가)/(나) 재채택, --dangerously-skip-permissions, force-push, git reset --hard, rm -rf, AWS 삭제/종료/SG/IAM, DB DROP/DELETE/UPDATE, 운영 배포, 시크릿 출력. - 진행: 필요 함수만 vendored 이식 → sara/codi_cli_runner.pycodi_run MCP 도구 → argv allowlist → stdin 합성(envelope+md+tail) → NDJSON 실시간 저장 → 모든 경로 ResultContract 발행 → git authority collector → push/tests regex 의존 제거 → codi_bridge.py에서 Agent 경로 대신 CLI runner 경로를 게이트 뒤 연결 → evaluator wrapper(evidence 없음·commit 없음 reject) → activity_logs/HandoffArtifact 내부 기록만, /chat 응답 불변. - 검증: 단위(dangerous flag 차단·repo missing 계약·crash mock 계약·stream-json parser·stall watchdog·git evidence collector·fake commit reject) + 통합(PROBE P-0~P-5 전부 통과). - 완료 보고: 수정 파일 / 커밋 해시 / 실행 테스트·결과 / PROBE별 pass·fail 표 / ResultContract 샘플 1 / broker 요청 수 근거 / 롤백 방법. - 롤백: SARA_CODI_CLI=0(게이트 OFF) → SARA 재기동 → vendored runner 미사용 복귀 → probe branch/파일은 승인 후 정리. - 성공 기준: PROBE P-0~P-5 pass / --dangerously-skip-permissions argv 0건 / broker 요청 실측 ≥1 / force-push 실 변경 0 / 실커밋 1건 git 검증 / evidence 없는 완료주장 reject / /chat 외부 응답 회귀 0. - 채티 보강: argv allowlist 단위테스트 명시 / NDJSON 경로 logs/codi_runs/<run_id>.ndjson+RDS pointer만 / untracked 보강은 별 PR 분리(본 PR은 partial_only 표기) / PROBE fail-safe(broker 0건=영구 차단).

5. .md 발행 전 선결 확인 (채티 직접 — 미확인 상태로 발행 금지)

  1. 공식 Claude Code 문서로 (a) claude -p.claude/settings.json PreToolUse 훅을 로드하는 정확한 조건, (b) --effort/--fallback-model 인자 정확 표기(--effort vs --reasoning-effort 등). GPT도 문서 직접 조회 못 함 → PROBE 전 SDK/CLI 문서로 사실 확정 후 .md에 박는다.
  2. cmdboard apply_codi_result 호출 시그니처 1회 더 대조 — SARA는 호출 안 하지만 evidence 필드명을 cmdboard 기존 payload 키와 맞춰야 ④ 공유정책(스키마 cmdboard 단일소유) 위반 0.

6. 메타