AI에게 코딩을 시키면 문제가 하나 있다. AI는 테스트도 안 해보고 "다 됐다"고 말한다. 그래서 사람들은 AI 옆에 자동 검문소를 붙인다 — 증거를 내놓기 전엔 "완료"로 인정하지 않는 장치다. 이걸 하네스(harness)라고 부른다. 이 글은 하네스 두 개를 비교한다. 하나는 남이 만든 gjc(별 2,043개를 받은 오픈소스 도구, 원저자 Yeachan-Heo), 하나는 내가 만든 bs-*(회사 서비스를 밤새 자동으로 굴리는 내 시스템)다. 둘은 서로를 모른 채 만들어졌는데 같은 결론에 도달했다 — 증거를 강제하지 않으면 AI는 조용히 거짓말을 한다. 다만 그 검문소를 정반대 위치에 세웠다. 이 글은 그 차이를 네 가지로 뜯어본다: 구조, 강점, 개선점, 문제점.
Identity
두 시스템은 무엇인가
Gajae-Code(줄여서 gjc)는 코딩을 대신 해주는 AI 프로그램을 통째로 직접 만든 것이다. 화면(TUI), AI에게 일을 시키는 루프, 각종 도구, 검문소까지 전부 한 프로그램 안에 들어 있다. 반대로 bs-*는 이미 있는 남의 프로그램(Claude Code)을 바깥에서 감싸 운영하는 방식이다. 할 일 목록은 GitHub의 작업 보드가 관리하고, 5분마다 시스템이 스스로 깨어나 일감을 집어 든다(macOS의 launchd가 이 "심장박동" 역할). 코드를 검사하는 규칙은 작은 스크립트가 강제한다. 목표는 똑같다 — "증거가 있어야 자율적으로 개발한다" — 다만 정반대 방향에서 출발했다.
2,043★gjc 받은 별 (7주 만에)
TS 2,908 + Rust 260gjc 코드 파일 수
4+4gjc 기능+역할 (고정)
9bs 보드-현실 맞추기 경로
15+bs 강제 검문 규칙
100+bs 축적된 규칙
gjc — 완성된 제품
쓸 수 있는 작업 방식을 딱 4개로 못박았다: 요구사항 캐묻기 → 계획 합의 → 실행 → 팀 분업. "기능을 함부로 늘리지 말 것"이 이 프로젝트의 규칙(AGENTS.md 파일에 명시)
작업 기록은 세션(한 번의 작업) 단위로 보관 — 계획·진행 장부·증거가 세션 폴더 .gjc/_session-*/ 안에 모인다
실행 전에 사람 승인을 받는다: 계획을 짜도 사람이 "OK" 하기 전까지는 승인 대기 상태로 멈춘다
배포 형태: 어느 운영체제에서나 도는 실행 파일, npm 패키지, 텔레그램·디스코드·슬랙 연동 키트
bs-* — 돌아가는 운영 시스템
작업 보드가 전체를 굴린다: 대기 → 배정 → 작업 → 합치기·배포 → 보드와 현실 맞추기 → 완료. 이 한 바퀴가 사람 없이 5분마다 돈다
기록은 세션이 끝나도 사라지지 않고 계속 쌓인다 — 작업 장부·표식·규칙이 누적되고, 여러 컴퓨터끼리 자동 동기화(cc-sync)된다
사람은 꼭 필요할 때만 부른다: 스스로 판단할 수 있는 건 알아서 하고, 정말 사람이 정해야 할 것만 콕 집어 질문으로 남겨둔다
쓰이는 곳: 회사 실서비스(BisFramework)에서 이슈 처리·배포·검증이 사람 손 없이 한 바퀴로 도는 실전 운영
Architecture — gjc
gjc: 캐묻고 → 계획하고 → 기록하며 실행
gjc의 작업 흐름은 한 단계씩 순서대로 가되, 중간에 사람 승인을 반드시 거치는 방식이다. 무엇이 진짜인지는 파일 두 개가 기준이 된다: goals.json(무엇을 목표로 하는지)과 ledger.jsonl(무슨 일을 했는지 지워지지 않게 차곡차곡 쌓는 "영수증 장부"). 그리고 "완료" 판정은 프로그램 자신이 직접 검사해서, 증거가 부실하면 완료로 인정하지 않는다.
gjc 작업 흐름 — 빨간 점선이 "사람 승인" 지점(계획에서 실행으로 넘어가는 관문). 완료를 검사하는 4개 검문소가 프로그램 안에 박혀 있어, AI가 말로 둘러대며 빠져나갈 수 없다.
Architecture — bs-*
bs-*: 작업 보드가 스스로 굴리는 무인 순환
bs-*는 쉬지 않고 도는 순환 고리다. GitHub 작업 보드가 할 일 목록이자 각 이슈의 현재 상태를 관리한다. 5분마다 배정 담당이 깨어나 "무엇부터 할지 분류 → 통과 검사 → 작업 실행"을 돌린다. 보드에 적힌 상태와 실제 코드가 어긋나면, "맞추기" 단계가 9가지 경우를 스스로 바로잡는다. 배포가 실패하면 복구 담당이 성공할 때까지 고치고, 매일 새벽 6시 17분엔 그날 있었던 실제 문제들을 훑어 "또 터질 신호"를 수집한다.
bs-* 순환 — 사람 없이 스스로 도는 고리. 초록 화살표가 "보드와 현실 맞추기"의 되먹임, 아래 두 줄이 실패 복구와 자가개선.
Core Insight
검문소는 어디에 있는가 — 누가 프로그램을 소유했는지가 위치를 정한다
두 시스템의 가장 큰 차이는 검문소를 "어디에" 두느냐다. 핵심 원리는 둘 다 똑같이 안다: AI에게 "거짓말하지 마"라고 글로 지시하는 건 소용없다. AI는 그 지시문마저 무시하거나 우회할 수 있기 때문이다. 진짜로 막으려면 AI가 손댈 수 없는 바깥에 검문소를 둬야 한다. gjc는 프로그램 전체를 자기가 직접 만들었기에, 검문소를 프로그램 안에 박아넣는다: "완료" 명령을 내려도 증거가 부실하면 그 명령 자체가 실패하고, "잠깐 멈춤"도 마음대로 못 하며, 역할마다 쓸 수 있는 명령이 미리 정해져 있다. 반대로 bs-*는 남이 만든 프로그램을 빌려 쓰기에, 바깥을 감싼다: 코드를 서버에 올리려는 순간 검문 스크립트가 가로막고(통과 못 하면 아예 못 올린다), 배정 담당이 증거를 확인하고, 배포 직전에 한 번 더 막는다.
gjc — 프로그램 안에 박힌 검문소
"완료" 명령(checkpoint)을 내리면 프로그램이 증거를 정해진 형식으로 검사한다 — 부실하면 명령 자체가 실패한다
역할(설계·기획·검토)마다 쓸 수 있는 명령이 미리 정해져 있어, 정해진 것 외에는 아예 실행되지 않는다
강점: 원리적으로 빠져나갈 틈이 없다. 약점: 자기 프로그램 바깥(외부 자동 테스트·작업 보드·배포)은 보지 못한다
bs-* — 프로그램 바깥을 감싼 검문소
코드를 올리거나 "완료"라고 선언하는 순간, 15개가 넘는 검문 스크립트가 가로막는다 — 통과 못 하면 물리적으로 올릴 수 없다
배정 담당이 증거를 확인한다: "수용 기준 충족", "막힌 이유", "오탐(잘못된 경보) 증거"가 없으면 다음 단계로 못 올라가거나 되돌려진다
서버에 올리기 전 검문 + 자동 테스트 통과 검사 + "배포까지 확인됐나" 검사를 모두 통과해야 "완료"로 승격된다
강점: 프로그램 바깥 세계(작업 보드·배포·자동 테스트)까지 관할한다. 약점: 여전히 글로 된 지시에 기대는 구간이 남아, 그곳은 우회될 여지가 있다
같은 원리, 다른 위치
"진짜 강제는 AI가 손댈 수 없는 바깥에 둬야 한다"는 원리를, gjc는 프로그램을 통째로 소유해서 달성하고, bs-*는 남의 프로그램을 바깥에서 감싸서 달성한다. gjc의 방식은 더 촘촘하지만 자기 프로그램 안에서만 통하고, bs-*의 방식은 성글지만 세계 전체(작업 보드·배포·다른 컴퓨터)를 덮는다.
Convergent Evolution
서로 모른 채 같은 것을 발명했다
두 시스템은 서로 참고한 적이 없다. 그런데도 똑같은 안전장치 6개를 각자 따로 만들어냈다. AI를 실제로 자율 운영하다 보면 부딪히는 문제가 똑같기 때문이다. 같은 답에 독립적으로 도달했다는 건, 그 장치가 우연이 아니라 반드시 필요한 것이라는 증거다.
공통으로 부딪힌 문제
gjc가 만든 장치
bs-*가 만든 장치
대충 "막혔다"고 하고 사람에게 떠넘기기
막힘을 "스스로 풀 수 있음"과 "사람이 필요함"으로 구분 — 스스로 풀 수 있는 건 멈추지 못하게 하고, 어느 쪽인지 장부에 기록해야만 멈출 수 있다
"스스로 판단 가능한가" 검문 + 막힘 증거 요구(질문 20자 이상·근거 2곳 이상) — 증거 없이 "막혔다"고 하면 다시 검사 대상으로 표시
"다 했다"는데 증거가 없음
완료 증거를 정해진 형식으로 검사(부실하면 명령 거부) + 영수증 기록
"수용 기준을 실제로 확인했다"는 증거를 강제 + 위·변조 방지용 서명
AI가 만든 지저분한 코드
지저분한 코드 정리기 — 문제 0이 될 때까지 돌린 뒤에야 리뷰로 넘어감
다른 AI(Codex)의 적대적 리뷰 + 코드 품질 검사 + 후퇴 방지 검문
기록은 지우지 않고 쌓기만 해야 함
영수증 장부 — 방향 수정도 정해진 6가지 방식만 허용하고, 목표 삭제는 금지
시도 기록 + 표식 + 변경 이력 파일 — 지우지 않고 더하기만 (덮어쓰기 금지)
텔레그램 봇이 중복 실행돼 충돌
상주 프로그램이 봇마다 딱 하나만 통신하도록 보장
"하나만 실행"을 보장하고 시작하는 규칙 (같은 사고를 직접 겪고 만듦)
시간이 오래 걸린 걸 "실패"로 잘못 판단
"기다림이 길어진 것은 지켜보는 시간일 뿐, 실패 신호가 아니다" — 규칙으로 못박음
시간 초과를 "일시적 오류"로 다시 분류 (137번 잘못 판단한 걸 확인하고 고침 — gjc보다 늦게 깨달음)
Strengths
각자가 압도하는 영역
gjc가 앞서는 것
증거의 종류를 강제하는 규칙 — 화면 종류(그래픽 화면·명령줄·앱·API)마다 어떤 증거를 내야 하는지 형식으로 못박는다. 명령줄 작업은 그대로 재실행해 다시 확인할 수 있고, 재현이 불가능한 예외는 사유를 7가지 코드로 남긴다
수용 기준 ↔ 테스트 연결표 — "요구사항 → 무엇으로 검증했나 → 어떤 공격 상황을 시험했나"를 하나하나 대응시킨다. "해당 없음"조차 이유를 반드시 적어야 한다
휴대폰에서 양방향 제어 — 텔레그램으로 "지금 필요한 결정"에 그 자리에서 답할 수 있다. 버튼·입력 표시까지 지원
검증 단위로 작업 묶기 — 같은 방식으로 검증되는 작업들을 하나로 합쳐 한 번에 확인한다. 제목이 비슷해서가 아니라 검증 기준이 같아서 묶는다
기능을 함부로 안 늘리는 규율 — 기능을 4개로 고정하고, 추가하려면 제품 차원의 결정과 검문 규칙 갱신이 필요하다. 지저분한 코드가 쌓일 자리를 원천 봉쇄
bs-*가 앞서는 것
사람 없이 스스로 돎 — gjc는 사람이 세션을 열고 승인해야 움직인다. bs-*는 5분마다 스스로 깨어난다: 밤새 이슈 7건을 나누고·합치고·승격하고·구현하고·병합하고·배포하는 데 사람 0명
코드 바깥 세계까지 관할 — 작업 보드 상태·배포 실행·자동 테스트·다른 컴퓨터까지 챙긴다. 배포가 실패하면 성공할 때까지 자동으로 고친다
보드와 현실을 스스로 맞춤 — 9가지 경로가 "보드에 적힌 상태 ≠ 실제 상태"인 어긋남을 매번 바로잡는다
세션을 넘어 학습 — 실수를 고친 기록이 규칙이 되고, 그 규칙이 다른 프로젝트로 퍼지고, 매일 재발을 감시한다. gjc의 기록은 한 세션 폴더 _session-* 안에 갇힌다
실전에서 검증된 이력 — 회사 실서비스에서 배포 실패 2회 자동 복구, 잘못된 "멈춤" 판정 17회 교정, 작업 137회 시간 초과를 근본 수리 — 이런 "사고와 수리" 짝이 전부 기록으로 남아 있다
Adoption Candidates
bs-*가 gjc에서 가져올 5가지
아래 다섯 가지는 전부 기존 bs-* 시스템에 덧붙이는 방식으로 가져올 수 있다 — 새로 만드는 게 아니라 이미 있는 검문소를 더 튼튼하게 하는 것이다.
1
증거의 종류를 정해두기 — 지금 내 완료 증거 파일은 형식이 자유롭다. gjc처럼 화면 종류마다 어떤 증거(스크린샷·터미널 기록·재실행·영수증)를 내야 하는지 형식으로 강제하면, "말로만 설명하고 통과"하는 구멍이 막힌다.
2
다시 돌려볼 수 있는 증거 — 지금 내 검증 증거는 스크린샷·로그라 나중에 다시 돌려볼 수 없다. 명령·기대 결과·조건을 함께 기록하면 언제든 재실행해 확인할 수 있다 — "검증 못 함"으로 남는 항목을 줄이는 직접적인 방법.
3
검증 기준으로 작업 묶기 — 지금은 제목이 비슷한 작업끼리 묶는데, 이게 매번 다시 섞이며 시간 초과를 키웠다(137회 실측). gjc처럼 "검증 기준이 같은 것끼리" 묶으면 그룹이 안정되고 검증이 한 번에 끝난다.
4
양방향 텔레그램 — 지금 내 알림은 한 방향뿐이고, 작업 재개는 보드에 댓글("## 결정")을 다는 우회 방식이다. 양방향으로 바꾸면 "결정해 달라"는 질문에 폰에서 바로 답하고 곧장 재개할 수 있다.
5
"왜 검증 못 했나"도 기록하기 — 재현이 불가능한 검증(라이브 배포 등)을 지금은 "검증 못 함" 한 줄로 남긴다. 이유를 정해진 코드와 "누가 승인했나"로 남기면, 못 한 이유까지 기계가 검사할 수 있다.
Weaknesses
정직한 문제점 — 양쪽 다
gjc의 문제
자율성에 천장이 있다 — 사람이 세션을 열고 승인하는 구조라, 사람 없이 24시간 도는 운영이 불가능하다. 사람이 없으면 아무 일도 시작되지 않는다
프로그램을 직접 소유하는 비용 — 화면·엔진을 통째로 만든 대가로 유지 부담이 크다. 자체 점검 보고서가 성능 결함 5건을 스스로 인정했다(화면을 갱신할 때마다 느려지는 재처리 등)
검문 범위가 자기 안에 갇힘 — 작업 보드·배포·자동 테스트처럼 프로그램 바깥의 실패는 설계상 관심 밖이다. "코드를 합친 뒤의 세계"를 챙기는 고리가 없다
기능을 묶어둔 대가 — 기능 4개로 고정한 덕에 지저분함은 막지만, 특정 분야에 맞춘 기능(예: BS의 권한 관리·배포 규약)을 담을 자리가 없다
할 일을 파일로만 관리한다 — 작업 보드·우선순위·담당자 배정 같은 팀 운영 화면이 없다
bs-*의 문제
글로 된 지시에 기대는 구간 — 일부 규칙은 프로그램이 아니라 AI에게 주는 글 지시라, 우회될 여지가 남는다. gjc였다면 프로그램이 아예 막았을 것을, 여기선 사후에 검사해서 잡는 구조다
"조용히 안 도는" 실패의 재발 — 분류 단계가 말없이 멈추거나, 없는 함수를 그냥 건너뛰거나, 감시 일정이 빠지는 등 "티 안 나게 멈추는" 결함이 반복 발견됐다(이번 주만 3건)
규칙이 100개 넘게 쌓임 — 규칙이 많다고 더 나아진다는 보장은 없다(관련 연구도 이 위험을 경고한다). 오래된 규칙을 걸러내는 장치가 있지만, 규칙 목록 자체가 지저분해질 수 있다
증거를 다시 돌려볼 수 없음 — 스크린샷·로그 위주라 나중에 재검증이 안 된다 (앞의 "가져올 5가지" 중 2번으로 개선 예정)
개선 효과를 한 번만 재보고 판단 — 시스템을 바꿔서 좋아졌는지를 단 한 번의 측정으로 결정하는 경우가 많다 (여러 번 재서 판단하는 규칙이 아직 전면 적용되지 않음)
Verdict
판정
두 시스템은 경쟁자가 아니라, 같은 명제를 각자 다르게 증명한 두 사례다 — "AI 자율 개발의 신뢰는 증거를 강제하는 구조에서 나온다"를, 하나는 프로그램을 통째로 소유해서, 하나는 남의 프로그램을 감싸서 증명했다.
종합
구조: gjc는 사람 승인을 거치며 한 단계씩 가는 방식, bs-*는 사람 없이 도는 순환 방식(사람은 예외 상황만 처리). 강점: gjc는 증거의 종류를 강제하는 규칙과 프로그램 내장 검문소, bs-*는 바깥 세계까지 챙기는 고리와 세션을 넘는 학습. 개선점: bs-*는 gjc의 증거 형식화·재실행 증거·검증 단위 묶기·양방향 텔레그램을 가져오면 된다(전부 기존 검문소의 강화). 문제점: gjc는 자율성 천장과 프로그램 소유 비용, bs-*는 글 지시 우회면과 조용한 실패 재발 — 결국 한쪽의 강점이 정확히 다른 쪽의 문제에 대한 답이다.