23.2 KB · 수정 2026-10-09 00:07
목차

cody-agent — 설계 (API 크레딧 우선 실행기)

[코디] 26.10.8(목) 1차 구축. 결정은 [페페], 검토 반영은 [코덱스]. 도구 = C:\dev\tools\cody-agent\ · 규칙 = rules.md · 상태 = handoff.md · devplan = C:\dev\devplan\cody-agent.html. 장부 = C:\dev\seedchain\rules\model-ledger.md §3 「tools · cody-agent」 L5(opus · max).

1. 목적 · 결정

2. 실측 사실 (26.10.8 · CLI 2.1.288 npm · VS Code 확장 2.1.292)

# 사실 근거
F1 잔액 조회 API 없음 — Admin/cost_report 401(개인 워크스페이스 키) → 로컬 원장으로 추정 상담 실측
F2 이 세션 env 를 그대로 물려준 claude -p --bare+키 = 400 「Credit balance is too low」 — 디버그 로그 x-anthropic-billing-header: … cc_entrypoint=claude-vscode · assistant error: billing_error · result api_error_status: 400 · 비용 $0. IDE 가 시작한 실행은 크레딧이 안 먹는다(구매분 $0 이라 400) — V2b probe_v2b.py(스크래치)
F3 env 를 허용목록으로 새로 만들면(CLAUDE*·ANTHROPIC_*·AI_AGENT 상속 0) CLI 가 스스로 cc_entrypoint=sdk-cli·cc_turn_origin=sdk 를 찍는다 → 크레딧 적용(성공) — V2a 바이너리 a.set("CLAUDE_CODE_ENTRYPOINT", e?"sdk-cli":"cli") · 디버그 로그
F4 키 주입 2안 모두 Bash 자식 env 에 키 없음: ①env ANTHROPIC_API_KEY+CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1(apiKeySource=ANTHROPIC_API_KEY) ②--settings {"apiKeyHelper": …}(apiKeySource=apiKeyHelper). 채택 = ② — 키가 claude.exe env 에조차 없다 probe_keys.py(스크래치, $0.0117)
F5 2.1.288 내장 도구 = Bash · Edit · Read 3개뿐(--tools Read,Edit,Write,Glob,Grep,Bash → init tools [Bash,Edit,Read]). --restricted 는 --tools 에 이름이 없으면 Bash 를 뺀다 init 이벤트
F6 --disable-slash-commands = init 의 skills 18→0 · slash 51→0(시스템 프롬프트 토큰 절약) init 이벤트
F7 CLI 단가표의 Sonnet 5.5 캐시 읽기 = $0.20(공식 $0.10) → total_cost_usd 가 약간 과대 → 정산은 max(CLI, 단가표)라 보수적 probe A 역산
F8 디버그 로그(--debug-file)에 키·프롬프트 본문이 없다(8KB, 빌링 헤더·요청 id 만) V2a
F9 공식 단가($/MTok, 26.10.8 pricing 페이지): Opus 5.5 4/20 · 쓰기 5m 5 · 1h 8 · 읽기 0.20 / Sonnet 5.5 2/10 · 2.5 · 4 · 0.10 / Haiku 5.5 0.10/0.50 · 0.125 · 0.20 · 0.01 (프롬프트 100k 초과 0.50/2.50 · 0.625 · 1 · 0.05) config.json prices
F10 CLI 에 claude-haiku-5-5 문자열 0건 → Haiku 의 total_cost_usd 불신, 자체 단가표 사용 상담 실측

2-1. 2차 (26.10.8 [코디] · L5 opus·max) — 구조 · 실측

구조(1차에 더한 것)

무엇 어디 요지
L4·L5 run run_task() · config budgets_usd(L4 $20 · L5 $30 · max $30) · timeouts_sec(3600 · 5400) · test_required_levels · review_required_levels --test 필수 · 결과 review_required · apply --reviewed. 예산 = 총괄 제안 15·25 → 실측 근거로 20·30(실제 L3 opus·high 큰 런 2건 = 30분 $5.71·$7.03, 분당 ≈$0.2 · xhigh·max 1.3~1.5배 × 60·90분)
권한 프로필 perm_profile() · config permissions L4·L5 = Bash 허용목록 / L1~L3 = Bash 전체 − 거부목록(1차 호환). 전 등급 = 거부목록 + --add-dir C:\dev(규칙 Read 용 · Edit(//c/dev/**) 거부 자동 = 읽기 전용) · {home} 치환
규칙 Read 강제 RUN_RULES «규칙 읽기» · rule_files_for() · resolve_project()(--project 또는 C:\dev 경로 조각) · rules_read_check() stream 의 Read tool_use + 성공 tool_result 로 판정(Bash cat 불인정 · 앞 구간과 OR) → 없으면 rules_read=false · 종료코드 7 · check 거부. ask = --with-rules(rules_digest() = CLAUDE.md 머리말·§2 + INDEX.md + 프로젝트 rules.md 머리, 16,000자 상한)
질문 릴레이 표 waits(추가형) · parse_questions() · create_wait() · list_questions() · answer_run() run 은 세션 저장(--session-id 고정) · ask 는 --allow-questions 때만. _claim_wait = waiting→answering 한 트랜잭션(rowcount 1 · 잡은 pid 가 죽은 answering 만 재획득) · TTL 72h · 사본·세션 파일 재확인 · decide() 재판정(하한·차단이면 waiting 으로 되돌림) · --resume 로 이어 실행. runs 행은 정산(settled · outcome=questions) 그대로 = 잔액 계산 불변
apply check check_run() = 런 상태 + patch_findings() + drift_check() + git apply --check 패치 내용 = ruleguard 탐지기 관점(heredoc 파일쓰기·.secrets·키·.claude 설정·ruleguard·git add -A·위험 명령·삭제·.env, 바이너리 = 표시만) · 원본 기준 = 패치 index 줄의 스냅샷 blob vs 원본 git hash-object(바이트·필터 둘 중 하나 일치) · HEAD 이동은 표시만. --force-check "사유" 기록
소진 페이스 compute_pace() → balance.json pace·waiting · C:\dev\tools\ctxmeter\ctx.py pace_part() 목표 = max(0, 오늘 시작 잔액 − 하한 − 예약) / 남은 일수(오늘 포함 · ≤1 이면 나누지 않고 전부). 오늘 시작 잔액 = 현재 + 오늘 정산액(하루 안에서 쓸수록 목표가 줄어드는 왜곡 방지). 마지막 날 하한 $2 = config 플래그만(기본 off)
위임 게이트 C:\dev\tools\cody-agent\agent_gate.py · C:\Users\delix\.claude\settings.json PreToolUse Agent|Task · config gate · state\gate.log gated = worker 5종 + opus-max-consult (+ 시험용 가짜 cody-agent-gate-selftest). 통과 = 표식 [구독]·[소작업] · 부작용형 키워드(뒤 14자 안 «금지·하지 마·없이…»면 무시) · 잔액−예약−그 등급 예산 < 하한(교착 방지) · 폴백·차단 · balance 못 읽음(fail-open)

실측(CLI 2.1.288 · 원장 기록 · 권한 시험 = Haiku 5.5 · 통합 시험 = 장부 등급 모델)

ID 무엇 결과
F11 --bare + --settings 로 넣은 PreToolUse 훅 안 돈다(마커 파일 0) → API 런 안의 차단 장치 = 권한 규칙뿐
F12 --disallowedTools 앞뒤 * 패턴 curl·Invoke-WebRequest·git push/fetch·pip install·-m pip·.secrets 거부 · 복합 명령(cd sub && curl·git status; curl)도 거부 · 거부가 허용을 이긴다
F13 허용목록 + --permission-prompts none 목록 밖(git commit·node·밖으로 cp/sed -i) = 자동 거부(「no approval surface」) · 읽기 전용 내장(whoami)·acceptEdits 의 cwd 안 rm/mkdir/리다이렉트 = 통과 · cwd 밖 rm·mv·rm -rf·git -C = 거부
F14 --restricted 파일 도구 Read/Edit = cwd + --add-dir 만 · Read/Edit(//c/**/.secrets/**) 거부 작동(미끼 파일 · 실제 .secrets 는 시험에 안 씀)
F15 Edit(<추가 폴더>/**) 거부 그 폴더의 Edit 도구 + Bash 파일쓰기 7종(rm·리다이렉트·sed -i·cp·mv·mkdir·touch) 전부 거부 — 허용목록·Bash 전체 허용 둘 다
F16 Bash 전체 허용(L1~L3) 거부 규칙 없는 cwd 밖 경로의 rm -rf = 통과(실측 삭제) → C:\dev·~\.claude·AppData\Roaming·Windows·ProgramData 를 Edit 거부로 막았다
F17 --add-dir 의 CLAUDE.md --bare 에선 안 실린다(디버그 「project memory is off」 · 카나리아 미노출)
F18 세션 저장 + --resume ~\.claude\projects\<cwd 슬러그>\<session_id>.jsonl · 같은 cwd 에서 --resume = 같은 session_id · 앞 대화 정확히 회상 · 새 run_id 의 apiKeyHelper 로 과금
F19 Edit 로 새 파일 old_string 빈 문자열 = 새 파일 생성(Write 도구 없음 보완)
F20 Haiku 5.5 CLI 비용 costBasis: unknown 대체 단가 → CLI $0.0955 vs 단가표 $0.0072(약 13배) — 원장 max() 가 과대 기록
F21 위임 모델의 자기 보고 거부된 git commit 을 «RAN» 이라 보고 → 판정은 stream tool_result
V8 최종 권한 프로필(config 그대로) L4 허용목록 17/17 · L1 9/9 기대대로(C:\dev 쓰기·~\.claude 쓰기·cd C:\dev·cd "C:\dev\pfs"·git -C·find -delete·powershell(L4)·.secrets·git commit 거부 / Read C:\dev\CLAUDE.md·mem_find·python·git status 허용) · L4 규칙 = 허용 58 + 거부 85 — CLI 가 전부 받아들임 · 미끼 파일 0
V9 L4 실 run(opus·xhigh · 임시 리포 mul 버그 · --project cody-agent) 규칙 3파일 Read → mem_find 2회 → 고치기 전 테스트 실패 확인 → Edit → 테스트 OK · 패치 242B(1줄) · $0.1956 · 28.8초 · 도구 11(오류 1 = 고치기 전 테스트) · apply = 거부(9 · 정독 필수) → --reviewed 적용 → 원본 테스트 OK
V10 질문 릴레이 실 run(L1 sonnet·medium) 1구간: 규칙 3파일 Read → QUESTIONS(존댓말/반말 · 추천 포함) → waiting(8) $0.069 · 5.9초 → questions 표시 → answer → 같은 session_id resume → greet.py 패치 → 테스트 「안녕, 페페」 → 0 · 2구간 $0.122 · 15.4초 · 두 번째 answer = 9 · check 0건 → apply 적용
V11 ask 질문 릴레이(Haiku · --with-rules --allow-questions) waiting(8) → answer → 같은 session_id resume → 「오후 15:00 으로 확정」 · 원장 $0.0478 + $0.0516(단가표 $0.011)
V12 agent_gate 실호출 서브에이전트(worker-opus-max) 안에서 Agent(가짜 타입) → deny(대체 명령 · gate.log 에 agent_id·agent_type) · [구독] 붙이면 통과 → 하네스가 「타입 없음」(실행 0) · 훅 63ms · settings.json 편집이 실행 중 세션에 바로 반영
모의 cody_agent.py selftest 169항목(1차 55 + 2차 114) 통과 · py3.12·py3.9 · ctx.py 37항목 · C:\dev\tools\cody_ask.py --selftest 11/11(어댑터 호환)

2차 실측 API 비용 합 = 원장 $1.01(보수 max) · 단가표 $0.45(14런: Haiku 권한 시험 7 · L4 1 · 질문 릴레이 2 · ask 릴레이 2 · devplan 대기 표시 확인 ask 2).

남은 위험(2차)

3. 구조

C:\dev\tools\cody-agent\
  cody_agent.py      CLI 겸 import 모듈(표준 라이브러리만 · py3.9 호환)
  key_helper.py      apiKeyHelper — 원장에서 «진행 중 API 런»일 때만 키를 stdout 에
  config.json        grant·floor·cycle·예산·시간·단가 (등급→모델은 여기 없다 = 장부 파싱)
  livecheck_task.py  숨김 예약작업 \Cody\cody-agent-livecheck 등록·실행(V2c 재검증)
  livecheck.vbs      wscript → pythonw cody_agent.py livecheck
  agent_gate.py      (2차) PreToolUse Agent|Task 조건부 차단 훅 — config gate · state\gate.log
  tests\selftest.py · tests\fake_claude.py
  state\ledger.sqlite(runs·anchors·events·meta + 2차 waits) · state\balance.json(+pace·waiting) · state\livecheck.json · state\gate.log   (git 제외)
  runs\<run_id>\  result.json · patch.diff · stream.jsonl · debug.log (git 제외)
%TEMP%\cody-agent\ask\       ask 의 cwd(빈 폴더 + 시스템 프롬프트 sys-<해시>.txt)
%TEMP%\cody-agent\<run_id>\work   run 의 사본

3-1. 경로 판정 = 한 트랜잭션

decide() = BEGIN IMMEDIATE 안에서 잔액 계산 → 판정 → 예약 행 INSERT. 동시 5건이 같이 하한을 뚫지 못한다(V6 실측: 잔액 14·예산 1·하한 10 → 정확히 4건 API · 1건 구독). - ask = API 불가면 구독으로 실행(재실행). allow_sub=False 면 실행 안 하고 kind=floor 실패. - run = API 불가면 실행 안 함 → 종료코드 3 「세션의 Agent 도구(장부 worker)로」.

3-2. 원장(state\ledger.sqlite, WAL)

3-3. 차단 오버레이(meta.block)

사유 감지 효력 해제
credit_low 결과·텍스트에 credit balance is too low(assistant billing_error, 400) 그 주기 끝까지 구독 1시간마다 probe(Messages API 1토큰) 성공 시
spend_cap specified API usage limits … regain access on <날짜> 그 날짜까지 자동(시각 경과)
auth authentication_failed·401 그 주기 끝까지 probe 성공 시

429 = retry-after(없으면 30초, 최대 120초) 대기 2회 → ask 는 구독. 5xx(overloaded·server_error) = 2회 재시도(5·10초) → ask 는 구독. max_budget(CLI error_max_budget_usd) = 실패 반환·재실행 없음.

3-4. 모드 · 알림

3-5. 실행(_run_claude)

claude.exe -p --output-format stream-json --verbose --no-session-persistence --disable-slash-commands
  --strict-mcp-config --restricted --setting-sources "" --permission-prompts none --model <전체 id> --effort <e>
  [API] --bare --max-budget-usd <상한> --settings {"apiKeyHelper": "pythonw key_helper.py --run <id>"}
  --tools "<프로필>" [--allowedTools …] [--permission-mode acceptEdits] [--system-prompt-file|--append-system-prompt-file]
프롬프트 = stdin(명령줄 32K 한도·프로세스 목록 노출 회피)

3-6. 편집 위임(run)

  1. git 리포면 git clone --shared --no-checkout + checkout --detach HEAD → 원본 작업트리의 수정·새 파일(무시 목록 제외)을 바이트 그대로 복사(삭제분은 사본에서도 삭제) → 사본에서 스냅샷 커밋 S. 원본 .git 에 흔적 0(worktree 목록 불변 실측). 비git 폴더 = 복사(500MB 한도) + 임시 git(core.autocrlf=false).
  2. 도구 = Bash,Edit,Read · acceptEdits · --permission-prompts none · 규칙 블록 주입.
  3. 끝나면 git add -A → git diff --cached --binary --full-index S = runs\<id>\patch.diff + --test 명령을 사본에서 실행한 결과 → result.json.
  4. 적용은 세션이 검토 후 apply <run_id> [--check](git apply --check → git apply). 자동 적용 없음.

4. 검증 (26.10.8 · 총 API 비용 ≈ $0.037 = 원장 기록 $0.0252 + 원장 생성 전 키 주입 비교 시험 $0.0117)

ID 무엇 결과 · 수치
V2a 허용목록 env + --bare + apiKeyHelper 성공 · apiKeySource=apiKeyHelper · cc_entrypoint=sdk-cli · $0.0002 · 디버그 로그에 키·프롬프트 없음
V2b 상속 env 그대로 + 키 400 「Credit balance is too low」 · cc_entrypoint=claude-vscode · $0 = IDE 분류 실증
V2c 숨김 예약작업 \Cody\cody-agent-livecheck(wscript→pythonw, Session 1) ask 성공(sdk-cli, $0.0002) · Bash 도구 1회 성공(sdk-cli, $0.0063) · 자식 env ANTHROPIC* 0 · claude PATH 없음 · 새 창 0(50ms 감시 13초)
V2d Messages API 직송(Haiku 5.5, 1토큰) 200
V2e 구독 경로(--force-sub) 성공 · apiKeySource=none
V-설정 cwd 에 .claude/settings.json·settings.local.json 로 가짜 ANTHROPIC_BASE_URL=http://127.0.0.1:9·ANTHROPIC_MODEL 을 심고 API 런 무시됨 — 성공 · 요청 모델 그대로 · 디버그 로그에 가짜 주소 0 · sdk-cli · $0.0002(사용자 설정도 같은 장치로 무시 — 전역 settings 는 안 건드려 직접 시험 안 함)
V5 앵커 10.5 → ask 구독으로 실행 · 모드 fallback · 알림 1회(broker 12:43:34 「API → 구독 폴백」) · 훅 · 구독 폴백 중 → 원복 앵커 198.674768 · 알림 「구독 → API 복귀」
V6 동시 5건·강제 kill API 4·구독 1 · 예약 합 4.0 · 정산 합 1.2 · kill 런 orphan(예약 2.0 유지) → recover --conservative
모의 400·max_budget·429·5xx·한도·인증·시간초과·결과 없음·init 전 사망·apiKeySource 불일치 55항목 통과(py3.12·py3.9 둘 다)
V7 ctx.py 훅(balance.json 없음·깨짐·주기 경과·Z 시각·NaN·sdk) 31항목 통과 · api_part 0.06ms/회 · 훅 프로세스 전체 39ms
위임 임시 git 리포 L1 버그 수정 원본 sha256 불변 · 패치 247B(calc.py 1줄) · 테스트 rc 0 · 자식 env ANTHROPIC* [] · claude 못 찾음 · $0.0185 · 16초 · apply --check→apply 후 원본 테스트 통과

5. 2차 이관 대상 (L4 회차 — 호출부마다 dry-run 후 재기동)

[코디] 26.10.8 23:40 KST 이관 완료 11곳(목록 밖 추가 3 = pfs kb-digest · devplan danggeun claude_json · devplan app.py 댓글) — 공용 어댑터 C:\dev\tools\cody_ask.py. 결과표 = handoff.md NOW · 보류 = fallback.py(대화형 세션엔 크레딧 불가) · 제외 = ainews judge(폐기) · 도구 필요 상주 4곳은 미결 4.

호출부 지금 메모
C:\dev\poin-agent\sgc\watcher.py · C:\dev\poin-agent\pfs_done.py claude -p(구독) 게시 창·halt→dry-run→재기동→watcher.py resume · 이벤트 id 로 중복 방지
C:\dev\talklog\server\ call_summary.py·pipeline_worker.py(분류)·night_worklog.py·fusion_post.py·talklog_server.py claude -p(구독) 월 ≈$100 추정(크레딧 절반) — Haiku 검토(F10·벤치 C:\dev\_bench\haiku55\) · py3.9
C:\dev\talklog\live\live_server.py claude -p
C:\dev\ainews-insta\judge.py claude -p
C:\dev\tools\session-relay\fallback.py OpenRouter 폴백 구독 한도 시 크레딧 Sonnet 고정으로 바꾸는 안
C:\dev\tools\stt\stt.py 교정 Haiku 검토

6. 남은 위험