가재코드는 무엇을 보고 판단하는가
오픈소스 코딩 에이전트 gajae-code(CLI는 gjc)의 소스를 직접 열어,
요청 한 줄이 인터뷰 → 계획 → 승인 → 실행 → 검증을 어떻게 통과하는지 끝까지 따라갔습니다.
관심사는 기능 목록이 아니라 판단입니다.
무엇을 근거로 결정하고, 그 근거를 어디서 모으고, 잘 모를 때 무엇을 하는가.
1. 한 장 요약
가재코드의 핵심 주장은 단순합니다. 에이전트가 실수하는 지점은 코딩이 아니라 판단이라는 것. 그래서 이 프로젝트는 모델을 더 똑똑하게 만드는 대신, 판단이 일어나는 자리마다 서로 다른 종류의 관문(gate)을 박아두고, 각 관문을 통과한 증거를 파일로 남깁니다.
요구가 모호할 때만 켜집니다. 한 라운드에 질문 하나씩, 가장 불명확한 항목만 찔러 모호도(ambiguity)를 수치로 떨어뜨립니다.
관문: 명료성 — 사용자가 원하는 걸 본인이 알고 있는가 · 산출물: 스펙 마크다운
Planner가 초안을 쓰고 Architect와 Critic이 각각 독립적으로 반박합니다. 두 심사가 같은 초안에 대해 동시에 통과해야 다음으로 갑니다.
관문: 타당성 — 접근법이 구조적으로 말이 되는가 · 산출물: ADR 포함 pending-approval.md
계획은 승인 전까지 제품 코드에 손대지 못합니다. 커밋·푸시·PR·실행 스킬 호출 전부 금지. 승인은 반드시 사람의 선택으로만 열립니다.
관문: 동의 — 사용자가 이 실행을 원한다고 명시했는가
목표를 goals.json에, 증거를 ledger.jsonl에 append-only로 씁니다. 완료 체크포인트는 구조화된 품질 게이트 JSON 없이는 CLI가 거부합니다.
관문: 증거 — 됐다고 말한 것이 실제로 실행됐는가 · 산출물: 리시트 스트림
tmux 워커를 여러 개 띄워 병렬 실행합니다. 자동으로 켜지지 않고, 사람이 명시적으로 고를 때만 붙습니다.
관문 없음 — 실행 엔진일 뿐, 목표·체크포인트 소유권은 ultragoal 리더가 유지
네 관문의 성격이 전부 다르다는 게 설계의 핵심입니다. 명료성(사람의 머릿속) → 타당성(설계) → 동의(권한) → 증거(실측). 하나를 건너뛰면 그 종류의 실패가 그대로 통과합니다. 인터뷰를 건너뛰면 엉뚱한 걸 잘 만들고, 계획을 건너뛰면 맞는 걸 이상하게 만들고, 승인을 건너뛰면 묻지도 않고 저지르고, 검증을 건너뛰면 안 된 걸 됐다고 보고합니다.
2. 판단 규칙은 어디에 적혀 있나
가장 먼저 확인한 것: 이 에이전트의 판단 기준이 TypeScript 안에 하드코딩돼 있는가, 아니면 읽을 수 있는 문서인가. 답은 후자입니다. 규칙 대부분이 마크다운 파일로 소스에 들어 있고, 런타임이 그걸 프롬프트로 조립합니다. 그래서 이 분석이 가능했습니다 — 코드를 역추적할 필요 없이 계약서를 그대로 읽으면 됩니다.
| 무엇 | 소스 위치 (packages/coding-agent 기준) | 역할 |
|---|---|---|
| 기본 헌법 | src/prompts/system/system-prompt.md | 정체성·라우팅·완료 계약·저장소 안전·도구 우선순위·검증 규칙 |
| 워크플로 4종 | src/defaults/gjc/skills/<name>/SKILL.md | deep-interview / ralplan / ultragoal / team의 전체 절차 |
| 역할 에이전트 4종 | src/prompts/agents/<role>.md | executor / architect / planner / critic의 권한·출력 계약 |
| 도구 설명 40여 개 | src/prompts/tools/*.md | read·search·bash·ask·patch 등 도구별 사용 규율 |
| 모드 프롬프트 | src/prompts/system/plan-mode-active.md | 계획 모드의 읽기 전용 강제와 탈출 조건 |
| 내부 프래그먼트 | src/defaults/gjc/skills/*/*.md | 불확실 자동응답·측면 검토 패널·슬롭 청소기 같은 온디맨드 조각 |
런타임 골격은 src/cli.ts → src/main.ts → src/sdk/session.ts로 흐릅니다.
세션 생성 시점에 설정·모델·인증·워크스페이스 컨텍스트·스킬·규칙·도구·시스템 프롬프트를 조립해
@gajae-code/agent-core의 에이전트 루프에 넘기고, 루프는
컨텍스트 변환 → 모델 스트림 호출 → 도구 실행 → 결과 append → 라이프사이클 이벤트를 반복합니다.
무거운 부분(AST 검색·grep/glob·PTY·셸·토큰 계산·문법 하이라이팅)은 Rust 크레이트(crates/pi-natives,
crates/pi-shell)로 내려 N-API로 붙입니다.
공부 포인트. "에이전트 프레임워크"라고 부르는 것들의 실체는 대개
프롬프트 계약 + 도구 레지스트리 + 상태 파일 셋입니다.
가재코드는 이 셋을 각각 src/prompts, src/tools, .gjc/로 아주 노골적으로 갈라놨습니다.
다른 에이전트를 뜯어볼 때도 이 세 자리를 먼저 찾으면 구조가 빨리 보입니다.
3. 요청이 들어온 순간의 분기
사용자가 뭔가를 말하면, 첫 판단은 "무엇을 만들까"가 아니라 "이걸 어느 무게로 다룰까"입니다.
시스템 프롬프트의 <routing> 블록이 그 분기표입니다. 요약하면 이렇습니다.
| 들어온 요청 | 판단 | 행동 |
|---|---|---|
| 명확하고 위험 낮은 구현 | 의식(ceremony) 불필요 | 도구로 바로 고치고 좁게 검증. 워크플로 호출 금지 |
| 대상·범위·수용기준·안전경계 중 하나가 빠진 구현 | 모호 | 변경 전에 확인하거나 계획 워크플로로 |
| 정보성 질문 | 답변 요청이지 실행 허가가 아님 | 읽기 전용으로 답만 |
| 요구 자체가 흐릿함 | 요구공학 문제 | /skill:deep-interview — 제품 코드 변경 금지 |
| 명확하지만 구조·순서 리스크가 큼 | 설계 문제 | /skill:ralplan --deliberate 후 승인 대기에서 정지 |
| 큰 구현 덩어리 | 혼자 하면 검증이 밀림 | executor에 위임, 리더는 검증 담당 |
"작은 검증이 필요하다고 해서 명확한 요청이 계획 워크플로로 바뀌지는 않는다."
src/prompts/system/system-prompt.md — <routing>이 한 줄이 생각보다 중요합니다. 절차가 촘촘한 시스템의 실패 모드는 절차 남용이거든요. 오타 하나 고치는 데 인터뷰 12라운드를 돌리면 아무도 안 씁니다. 그래서 deep-interview 스킬 본문에도 Phase 0.5 적합성 게이트가 따로 있습니다. 요청이 이미 명확·작음·저위험이면 인터뷰를 즉시 중단하고, 상태를 지우고, "이건 인터뷰 대상이 아니다, 그냥 이렇게 고치면 된다"고 말하고 빠져나오게 되어 있습니다. 스킬 안에 자기 자신을 끄는 조항을 넣어둔 셈입니다.
같은 정신이 ralplan의 사전 게이트에도 있습니다. team fix this, team improve performance처럼
앵커가 없는 실행 요청은 계획으로 되돌리고, 파일 경로·이슈 번호·심볼명·테스트 러너·번호 매긴 단계·수용 기준 중
하나라도 있으면 통과시킵니다. 오탐이면 앵커를 하나 붙이거나 force:/!로 우회하라고 명시해 둡니다.
4. e2e 전 구간 따라가기
여기서부터가 본론입니다. 각 단계에서 어떤 판단을 하고, 무엇을 근거로 삼고, 무엇을 파일로 남기는지를 순서대로 봅니다.
STAGE 1 · 관문: 명료성deep-interview — 모호함을 숫자로 깎는다
인터뷰는 "궁금한 걸 물어보는" 게 아니라 모호도를 목표치 아래로 떨어뜨리는 최적화 루프로 설계돼 있습니다.
- Phase 0 — 임계값부터 확정. 설정 파일 우선순위를 따라
ambiguityThreshold를 읽고, 해석한 값과 출처를 사용자에게 첫 줄로 공개합니다(기본 0.05,--quick0.6 /--standard0.5 /--deep0.35). 판정 기준을 몰래 쓰지 않고 먼저 공시한다는 뜻입니다. - Round 0 — 토폴로지 확정. 점수를 매기기 전에 "내가 이해한 최상위 구성요소는 N개다"를 먼저 확인받습니다. 자세히 설명된 한 덩어리가 나머지 형제 구성요소를 삼켜버리는 걸 막는 장치입니다.
- Phase 2 — 라운드당 질문 하나. 네 차원(목표 명료성 / 제약 / 성공 기준 / 브라운필드 맥락) 중 가장 점수가 낮은 구성요소·차원 쌍만 겨냥하고, 왜 지금 그게 병목인지 한 문장으로 밝힌 뒤 묻습니다. 질문 여러 개를 묶어 던지는 건 명시적으로 나쁜 예로 박제돼 있습니다("답이 얕아지고 채점이 부정확해진다").
- 모호도는 내려가기만 하지 않는다. 답변이 기존 사실과 모순되거나(A), 내부 불일치를 만들거나(B), 회피성이거나(C), 범위를 넓히면(D) 해당 차원 점수를 떨어뜨려 모호도를 다시 올립니다. 수렴을 가정하지 않는 양방향 채점입니다.
- 확정된 사실은 지우지 않는다. 안정된 결정은
established_facts로 승격되고, 나중에 모순이 생기면 삭제하는 대신 분쟁 상태로 표시합니다. 새 방향이 확정될 때superseded_by로 이어 붙여야만 수렴 압력이 풀립니다. - 온톨로지 수렴. 매 라운드 등장한 엔티티를 추출해 이름이 얼마나 안정됐는지(stability ratio) 추적합니다. 핵심 명사가 계속 흔들리면 기능 질문 대신 "이건 근본적으로 무엇인가"를 묻는 존재론 질문으로 전환합니다.
- 측면 검토 패널. 모호도 구간이 바뀔 때마다
researcher·contrarian·simplifier(구조가 바뀌었으면architect까지)를 서로의 답을 못 보는 병렬 읽기전용 서브에이전트로 띄웁니다. 서로의 프레임에 닻 내리는 걸 막으려는 의도. 이들은 질문을 늘리지 않고, 다음 한 질문의 선택지로만 접힙니다. - 수학을 완료로 취급하지 않는다. 임계값을 넘겨도 Phase 4에서 종결 심사가 한 번 더 돕니다. "수치는 준비됐다고 하지만, 나는 아직 받아들이지 않겠다 — 이유는 X"라고 사람에게 되돌릴 권한이 명시돼 있습니다. 마지막엔 합의된 내용을 한 문장으로 접어 "이 한 줄만 읽어도 같은 결과에 도달하겠습니까?"를 확인받습니다.
산출물은 .gjc/_session-<id>/specs/deep-interview-<slug>.md 한 장.
목표·제약·비목표·수용 기준뿐 아니라 노출되고 해소된 가정 표, 트리거 이력, 온톨로지 수렴표,
전체 질의응답 기록까지 들어갑니다. 나중에 "왜 이렇게 정했지?"를 되짚을 수 있게 만든 문서입니다.
STAGE 2 · 관문: 타당성ralplan — 합의 없이는 계획이 아니다
ralplan은 계획을 쓰는 워크플로가 아니라 계획을 반박시키는 워크플로입니다.
- Planner는 한 번만 띄우고 계속 재개한다. 매 패스마다 새로 뽑지 않고 같은 서브에이전트를 resume해 누적된 반박을 먹입니다. 재개가 불가능한 경우(컨텍스트 소실·프로세스 재시작 등)에만 새로 띄우고, 왜 폴백했는지를 메타데이터로 기록합니다.
- Architect와 Critic은 서로를 보지 않는다. 같은 불변 초안(경로+sha256+패스 번호)에 대해 독립적으로 심사합니다. Critic이 Architect의 결과를 평가해야 하는 경우에만 순차로 돌립니다.
- 두 판정이 같은 초안에 대해 함께 깨끗해야 통과. Architect는 CLEAR/WATCH/BLOCK과 APPROVE/COMMENT/REQUEST CHANGES를, Critic은 OKAY/ITERATE/REJECT를 냅니다. 한쪽만 보고 마무리하는 건 금지.
- 무한 루프 대신 정직한 실패. 합의 반복은 기본 5회가 상한이고, 런타임이 강제합니다.
초과하면 종료코드 3과
PLANNING-STUCK을 뱉고 자동 실행으로 넘어가지 않습니다. 대화형이면 지금까지의 최선안을 사람에게 보여주고 멈춥니다. - 합의 후에 의도 재대조. 통과했다고 바로 끝내지 않고,
루프가 사실이 아니라 가정으로 메운 항목과 이전 스펙과 충돌하는 지점을 모아 하나씩 사용자에게 확인합니다.
확인 결과는 최종 문서의
## Intent Reconciliation절에 박혀 남습니다. - 최종 산출물은 ADR. 결정·결정 동인·검토한 대안·왜 그걸 골랐는지·결과·후속 과제. "무엇을 할지"만이 아니라 "무엇을 안 하기로 했고 왜인지"를 남기는 형식입니다.
STAGE 3 · 관문: 동의승인 — 기본값은 "실행하지 않음"
이 프로젝트에서 가장 단호한 규칙이 여기 있습니다. 승인 전 계획·인터뷰 워크플로는
제품 소스 편집, 변경성 셸 명령, 커밋, 푸시, PR 열기, 구현 위임을 전부 금지당합니다.
문서에만 적힌 게 아니라 .gjc/ 경로에 대한 직접 쓰기까지 코드로 막혀 있고,
계획 산출물은 전용 CLI writer를 통해서만 기록됩니다.
별도의 계획 모드도 같은 형태입니다. 읽기 전용으로 잠긴 상태에서 계획 파일을 증분 갱신하다가,
resolve(apply)를 에이전트 스스로 호출해야 사용자 승인 UI가 열립니다.
"계획 모드 좀 꺼주세요"라고 사용자에게 부탁하는 것도 금지돼 있습니다.
"허락을 구걸하는 표현을 쓰지 마라. 파괴적인 다음 단계라면 권장안을 말하고 멈춰라. 파괴적이지 않고 명백히 옳은 단계라면 같은 턴에서 바로 하라."
src/prompts/system/system-prompt.md — <communication>이 두 규칙("승인 전엔 절대 안 건드림" + "승인 필요 없는 일은 묻지 말고 바로 함")이 한 문서에 같이 있다는 게 포인트입니다. 느슨한 에이전트는 아무거나 저지르고, 소심한 에이전트는 매번 물어서 사람을 지치게 합니다. 경계선을 파괴성으로 그은 것이지 불확실성으로 그은 게 아닙니다.
STAGE 4 · 관문: 증거ultragoal — "됐다"는 말은 리시트로만 인정
실행 단계의 전제는 노골적으로 불신입니다. 인라인 목표 상태는 UX 표시용일 뿐이고,
완료 판정은 오직 durable 파일에서만 나옵니다.
goals.json이 목표 정체성과 상태, ledger.jsonl이 append-only 증거 스트림입니다.
완료 체크포인트를 찍기 전에 강제되는 게이트가 이만큼입니다.
- 구현 검증 먼저
해당 스토리 범위의 표적 검증을 실제로 돌립니다.
- 슬롭 청소기 통과
내부 프래그먼트
ai-slop-cleaner가 변경된 파일만 읽고 숨은 폴백·중복·죽은 코드·불필요한 추상화·경계 위반·빠진 테스트를 차단/권고로 분류합니다. 차단 항목이 0이 될 때까지executor가 고치고 다시 돌립니다. 청소기 자신은 읽기 전용입니다. - 청소 후 재검증
정리된 코드 기준으로 검증을 다시 돌려야 심사 대상이 최신이 됩니다.
- Architect 3레인 리뷰
아키텍처(경계·계층·데이터 흐름) / 제품(사용자 눈에 보이는 동작·수용기준·회귀) / 코드(유지보수성·테스트·위험한 지름길)를 각각 판정합니다.
- Executor 레드팀
해피 패스 확인이 아니라 깨뜨리려는 레인입니다. 승인된 계획·수용기준에서 출발해 사용자 계약을 보고, 구현 코드는 마지막 보조 증거로만 봅니다. 계획과 코드가 어긋나면 그건 블로커이지 넘어갈 항목이 아닙니다.
- 표면에 맞는 증거 제출
여기가 이 프로젝트에서 가장 깐깐한 부분입니다(아래 표).
- 종결 Critic 게이트
실행 종료(완료 또는 일시정지) 직전에 읽기 전용 Critic이 한 번 더 전체를 봅니다. OKAY가 아니면 종료 자체가 막히고, 비-OKAY 누적 5회면 사람의 명시적 오버라이드 없이는 완료도 정지도 못 합니다.
| 무엇을 고쳤나 | 인정되는 증거 |
|---|---|
| GUI · 웹 | 자동화 트랜스크립트 + 균일하지 않은 스크린샷. 텍스트 설명만으로는 불인정 |
| CLI | 런타임 argv 재생: 허용목록 명령·기대 종료코드·기록된 출력·불변식 검사가 담긴 cli-replay JSON |
| 네이티브 · 데스크톱 · TUI | 구조적으로 유효한 스크린샷, 제어문자 포함 PTY 캡처, 앱 자동화 기록 |
| API · 패키지 | api/package/consumer/black-box/test-report류 아티팩트 파일 또는 타입드 리시트 |
| 알고리즘 · 수학 | property/boundary/edge/adversarial/failure류 아티팩트 |
재생 불가한 명령(자격증명·네트워크·파괴적·비결정적)은 replayExempt에
사유코드·사유·승인자·대체 아티팩트를 적어야만 예외로 인정됩니다. 예외에도 서명을 요구하는 구조입니다.
막혔을 때의 규율도 인상적입니다. 실행 중 블로커는 두 종류로 분류됩니다.
해결 가능(실패한 테스트, 미구현, 의존성 설치, 추론 가능한 모호함)이면 절대 멈추지 않고
조사하거나 하위 목표를 추가하거나 executor에 위임하거나 블로커를 durable하게 기록하고 다음 목표로 갑니다.
사람만 할 수 있는 일(자격증명, 물리적 작업, 외부 승인)일 때만 정지가 가능한데,
그마저도 분류 기록 → 종결 Critic의 OKAY → 그 다음에야 pause입니다.
Critic은 "로컬에 자원이 있는데 사람 탓으로 돌리는 가짜 정지"를 잡아내라고 지시받습니다.
그리고 실행이 도는 동안 ask 도구는 아예 차단됩니다 — 애매하다고 사람을 붙잡는 대신 블로커로 적으라는 뜻입니다.
위임 기준도 수치화돼 있습니다. 3개 이상 파일, 분리 가능한 표면 2개 이상, 순변경 200줄 내외 이상, 또는 리더가 이미 인라인 편집을 2회 했는데 아직 미완이면 executor 위임이 의무이고, 혼자 처리하면 그것 자체가 게이트 위반으로 취급됩니다. 리더의 본업은 코딩이 아니라 검증이라는 선언입니다.
5. 판단 근거를 어떻게 모으나
"근거를 모은다"가 이 시스템에서는 세 겹으로 구현돼 있습니다. 찾는 규율, 읽은 것을 고정하는 장치, 남기는 형식.
겹 1 — 찾는 규율
"희망을 갖고 파일을 열지 마라. 대상을 먼저 특정하라."
src/prompts/system/system-prompt.md — <exploration>- 이름·글롭으로 위치를 좁히는 도구(
find)와 내용 정규식(search)을 먼저 쓰고,read는 구간으로 읽습니다. 파일 전체를 통째로 삼키지 않습니다. - 셸 coreutils(
cat·grep·sed·ls등)로 파일을 다루는 것이 금지돼 있습니다. 전용 도구가 구조화된 결과와 앵커를 주기 때문입니다. - 구조가 중요한 탐색은 정규식 대신 AST 도구를, 심볼 참조는 LSP를 먼저 쓰라고 못박습니다.
내보낸 심볼을 고치기 전에
lsp references를 돌리는 것도 규칙입니다. - 독립적인 조회는 같은 턴에서 병렬로 던지라고 지시합니다. 왕복 횟수를 줄여 컨텍스트를 아끼는 최적화입니다.
- 도구 실패했거나 파일이 바뀌었을 수 있으면 행동 전에 다시 읽어라는 조항이 따로 있습니다.
겹 2 — 읽은 것을 고정하는 장치
가재코드의 파일 편집은 줄 번호만으로 하지 않습니다. 구간을 읽으면 각 줄 앞에 줄번호 + 2글자 내용 지문(hashline anchor)이 붙어 나오고, 편집은 그 앵커를 인용해야 합니다.
41th|def alpha():
42sx| return TITLE
앵커를 지어내면 편집이 거부되고, 파일이 바뀌었으면 앵커가 어긋나 실패합니다. 즉 "내가 방금 실제로 읽은 내용"과 "내가 고치려는 대상"이 같다는 것을 기계가 검증합니다. 환각으로 없는 코드를 고치는 사고를 형식 자체로 막는 접근이고, 개인적으로 이 프로젝트에서 가장 영리한 부분이라고 봅니다.
같은 정신이 출력 처리에도 있습니다. 셸 출력이 길어 잘리면 원본 전체가 artifact://<id>로 보존되고,
요약본이 의심스러우면 그 아티팩트를 읽어 실제 바이트를 확인하라고 안내합니다.
잘린 출력을 근거로 결론 내리지 말라는 규칙입니다.
겹 3 — 남기는 형식
| 누가 | 무엇을 제출해야 하나 |
|---|---|
| Architect | 중요한 주장은 구체적 파일/검사한 증거를 인용. 검사하지 않은 코드·계획은 승인 금지, CRITICAL·HIGH 승인 금지, 이 코드베이스와 무관한 일반론 금지 |
| Critic | 계획이 참조한 파일을 실제로 열어 검증하고, 대표 구현 과제 2~3개를 머릿속으로 시뮬레이션. "확실히 없음"과 "불확실함"을 구분해서 보고 |
| Executor | 바꾼 파일 목록 + 각 파일의 목적 한 줄, 구현 결정과 가정, 수행한 검증(또는 부모에게 남기는 정확한 검증 지시), 미해결 블로커 |
| Planner/Architect/Critic (ralplan) | 본문은 CLI로 영속화하고 회신은 run_id·path·sha256 리시트만. 부모 대화에 원문을 도배하지 않음 |
| ultragoal 리더 | 체크포인트마다 품질 게이트 JSON(아키텍트 3판정 + 레드팀 매트릭스 + 재실행 결과), 최종엔 Critic 판정까지 |
읽기 전용 역할들은 권한도 실제로 좁혀져 있습니다. Architect·Critic의 bash는 허용 접두사 목록으로 잠겨 있어
git status·log·show·diff·blame 같은 조회와 워크플로 기록 명령만 가능합니다.
"읽기 전용"을 프롬프트로 부탁하는 게 아니라 실행 환경으로 강제합니다.
완료 계약(completion contract)도 근거 이야기입니다. 부분 작업을 완료로 보고하지 않기, 테스트·경고를 억누르지 않기, 관측하지 않은 출력·테스트·소스 사실을 지어내지 않기, 요청받은 문제를 더 쉬운 옆 문제로 바꿔치기하지 않기, 스텁·플레이스홀더·가짜 폴백을 기능으로 납품하지 않기, 그리고 "검증했다는 주장은 실제로 실행한 것과 일치해야 한다". 이 목록은 전부 LLM 코딩 에이전트가 실제로 저지르는 사고의 카탈로그입니다.
6. 잘 모를 때는 어떻게 하나
가장 궁금했던 대목입니다. 대부분의 에이전트는 모를 때 둘 중 하나를 합니다 — 그럴듯하게 지어내거나, 모든 걸 사람에게 되묻거나. 가재코드는 불확실성의 종류에 따라 다른 대응을 지정합니다. 정리하면 이런 사다리입니다.
- 먼저: 사실인가 결정인가
현재 스택, 버전, 기존 패턴, 외부 API 제약 같은 사실 질문은 탐색·조사로 스스로 답하고, 근거를 인용한 "확인 요청"으로만 제시합니다. 목표·범위·트레이드오프·원하는 동작 같은 결정은 사람에게 보냅니다. 둘 중 뭔지 헷갈리면 결정으로 취급해서 묻습니다. 애매할 때 사람 쪽으로 기울이는 기본값입니다.
- 사실인데 모르겠다: 근거가 줄어들 때까지 더 찾는다
"정황상 그럴듯한 첫 답에서 멈추지 마라. 한 번 더 조회해서 불확실성을 줄일 수 있으면 그렇게 하라"가 도구 정책의 첫 문장입니다. 코드베이스가 알려주는 걸 사용자에게 묻는 것은 나쁜 예로 못박혀 있습니다.
- 결정인데 물을 수 없다: 가장 보수적인 가정을 세우고 표시한다
사용자가 답변을 넘기거나 "네가 정해"라고 하면
auto-answer-uncertain프래그먼트가 뜹니다. 읽기 전용 아키텍트가 하나의 결정적 답을 JSON으로 돌려주는데, 필수 필드가answer, 근거 2~4개의rationale,confidence, 그리고uncertainty(남은 불확실성)입니다. 선택 기준은 "사용자 의도를 보존하면서 되돌릴 수 없는 가정을 피하는 가장 보수적인 답". - 모르는 채로 점수를 올리지 않는다
자동 응답으로만 좋아진 차원은 확신이
high이고 잔여 불확실성이 무시할 수준이 아닌 한 0.85를 넘지 못하게 상한이 걸립니다. 그 자동 응답 때문에 임계값을 넘게 되면, 가정을 사람 앞에 꺼내 명시적 확인을 받아야만 다음 단계로 갑니다. - 근거가 정말 없으면: 추측 금지
프래그먼트의 폴백 조항이 명시적입니다. "방어 가능한 답을 낼 만큼 맥락이 부족하면 추측하지 마라. 되돌릴 수 있는 가장 안전한 기본값을 내고, 확신을
low로 표시하고, 실행 승인 전에 사용자가 반드시 확인해야 할 것을 분명히 지목하라." - 자동 해결이 연달아 3번이면 강제로 사람에게
"대화 리듬 가드"라는 이름이 붙어 있습니다. 자동 조사·자동 응답으로 라운드가 연속 3번 해결되면, 다음 질문은 자동으로 답할 수 있어 보여도 사람에게 보냅니다. 이유가 한 줄로 적혀 있습니다 — "인터뷰의 상대는 코드베이스가 아니라 사람이다."
- 모호함이 늘어났으면 늘어났다고 인정한다
양방향 채점, 분쟁 사실 보존, 미채점 구성요소 압력이 모두 여기 해당합니다. 진행률이 뒤로 가는 걸 허용하는 시스템은 드문데, 이건 명시적으로 허용합니다.
- 실행 중 막혔으면: 멈추지 말고 기록한다
실행 단계에서
ask는 차단됩니다. 해결 가능한 블로커는 하위 목표 추가·위임·조사로 계속 밀고, 사람만 풀 수 있는 것만 분류 기록 + Critic 승인 후 정지. 미해결 판단은 대화로 흘리지 않고 durable 블로커로 남깁니다. - 소스 자체를 못 얻으면: 얻은 만큼으로 산출물을 낸다
영상·오디오 같은 장문 소스 처리 규칙이 좋은 예입니다. 전사(transcript) 확보에 2회 실패하면 거기 매달리지 말고 가용한 증거로 결과물을 만들되 "사용한 증거"와 "한계"를 명시하라고 지시합니다. 완벽한 입력을 얻는 것이 결과물을 내는 것의 전제조건이 아니라는 선언입니다.
- 구현이 안 풀리면: 접근을 바꾸고, 쪼개고, 그래도 안 되면 블로커로 보고
Executor의 실패 복구 조항. "실질적으로 다른 접근을 여러 번 실패했다면 위험을 더 쌓지 말고, 시도한 것들과 함께 블로커를 보고하라." 무한 재시도를 미덕으로 두지 않습니다.
한 줄로 요약하면 이렇습니다. 모르는 걸 아는 척하지 않고, 그렇다고 모른다는 이유로 멈추지도 않는다. 대신 모르는 정도를 값으로 들고 다니면서(confidence, uncertainty, ambiguity, floor, disputed) 그 값이 결과물의 다음 관문을 통과할 수 있는지로 판단합니다.
7. 왜 이렇게까지 하나 — 해석과 비판
여기부터는 소스에 적힌 사실이 아니라 제 판단입니다.
이 설계 전체가 겨냥하는 단 하나의 실패 모드가 있습니다. LLM은 "그럴듯한 완료"를 아주 싸게 생산한다는 것. 코드는 컴파일되고, 요약은 매끄럽고, 테스트는 "통과했다"고 적혀 있는데 실제로는 아무것도 검증되지 않은 상태. 가재코드의 처방은 세 가지입니다.
판단을 외부화
언제 묻고 언제 그냥 하는지를 모델의 재량이 아니라 읽을 수 있는 계약으로 옮겼습니다. 그래서 고칠 수 있고, 감사할 수 있고, 이렇게 분석할 수도 있습니다.
관문마다 다른 검증
명료성·타당성·동의·증거는 서로를 대체하지 못합니다. 같은 종류의 심사를 네 번 하는 게 아니라 네 종류의 실패를 각각 잡습니다.
증거를 파일로
대화는 사라지고 요약은 왜곡됩니다. sha256 리시트와 append-only 원장은 나중에 다시 검증할 수 있는 형태로 남습니다.
그래서 좋기만 한가 — 아니요
- 무겁습니다. 관문 하나하나가 서브에이전트 호출이고 토큰이고 시간입니다. 작은 작업까지 이 파이프라인에 태우면 손해가 명백합니다. 그래서 적합성 게이트가 존재하지만, 그 게이트가 제대로 작동하느냐는 결국 모델의 판단에 다시 의존합니다.
- 규칙이 규칙을 부릅니다. ultragoal 스킬 문서만 400줄이 넘고, 품질 게이트 JSON 스키마는 중첩이 상당합니다. 사람이 이 계약 전체를 머리에 담고 디버깅하기는 쉽지 않습니다.
- 문서와 구현의 괴리 위험. 이렇게 많은 규율을 프롬프트로 표현하면 "적혀 있지만 실제로는 강제되지 않는" 조항이 생기기 쉽습니다. 다만 이 프로젝트는 상당수를 런타임 강제(반복 상한, 게이트 JSON 거부, pause 차단, bash 접두사 제한)로 내려놨고, 그 점은 인정할 만합니다.
- 여전히 실험적 베타입니다. 저장소가 스스로 그렇게 밝히고 있습니다. 중요한 작업에 쓰려면 결과를 직접 검증하라는 경고를 README 맨 위에 달아둔 상태입니다.
그럼에도 공부 대상으로서의 가치는 분명합니다. 다른 도구를 쓰더라도 "이 결정의 근거는 무엇이고, 어디에 증거가 남는가"를 묻는 습관은 그대로 옮겨갑니다. 에이전트에게 일을 시킬 때 가장 위험한 순간은 에이전트가 틀렸을 때가 아니라, 틀렸는지 맞았는지 확인할 방법이 없을 때니까요.
8. 직접 확인해보기
이 글의 내용은 전부 여러분 컴퓨터에서 확인할 수 있습니다. 설치돼 있다면 프롬프트 원문이 디스크에 그대로 있습니다.
gjc skills list # 기본 워크플로 4종 목록
gjc skills read ralplan # 합의 계획 스킬 원문 그대로
gjc setup defaults --check # 내 .gjc 사본이 번들 기본값과 다른지 비교
cd ~/.bun/install/global/node_modules/@gajae-code/coding-agent/src
cat prompts/system/system-prompt.md # 헌법: 라우팅·완료 계약·검증
cat defaults/gjc/skills/deep-interview/SKILL.md # 인터뷰 전 절차
cat defaults/gjc/skills/ralplan/SKILL.md # 합의 루프와 반복 상한
cat defaults/gjc/skills/ultragoal/SKILL.md # 품질 게이트와 증거 규칙
cat prompts/agents/architect.md # 읽기 전용 심사자의 권한 경계
cat defaults/gjc/skills/deep-interview/auto-answer-uncertain.md # 모를 때의 규칙
gjc ultragoal status --json # 목표별 상태
# 세션 산출물이 쌓이는 곳
# .gjc/_session-<id>/specs/ 인터뷰 스펙
# .gjc/_session-<id>/plans/ ralplan 단계별 아티팩트 + pending-approval.md
# .gjc/_session-<id>/ultragoal/goals.json, ledger.jsonl
공부 순서 추천. ① system-prompt.md의 <routing>과
<completion-contract>만 먼저 읽으세요(합쳐서 30줄 남짓인데 설계 의도의 절반이 여기 있습니다).
② 그다음 ralplan/SKILL.md의 합의 루프 5단계.
③ 마지막으로 ultragoal/SKILL.md의 "Mandatory completion cleanup and review gate" 절.
이 셋만 읽어도 "판단 → 검토 → 증거"의 뼈대가 잡힙니다.
main의 문서를 직접 열어 정리한 독립 분석입니다.
gajae-code는 cmore.dev와 무관한 외부 오픈소스 프로젝트이고, 이 페이지는 보증이나 공식 문서가 아닙니다.
프로젝트가 스스로 밝히듯 실험적 베타 단계라 세부 규칙은 버전마다 바뀔 수 있으니,
중요한 판단은 위 명령으로 본인 환경의 실제 파일을 확인하고 하세요.