DEV24 SEP 2026 — [24 MIN]

폴리데우케스 — 하네스에도 공통 언어가 필요하다

실행 그래프를 설계하는 시대, 하네스에도 공통 언어가 필요하다. 규율에 이름을 붙이고 실행 기록으로 워크플로우를 개선하려는 Polydeukes의 시도.

1. 코드를 잘 쓰는 모델 다음의 문제

2026년 9월, 내가 개발 도구에 요구하는 기준은 사람이 계속 붙어 있지 않아도 구현이 다음 단계로 진행되는가다. 요구사항을 받아 코드를 고치고, 검증에 실패하면 원인을 찾아 다시 시도하고, 정해 둔 완료 조건까지 도달하는 것. 이제 내가 설계하는 개발 환경에서 인간 개입 없는 구현은 기본 요구사항에 가깝다.

이 기준으로 보면 관심의 단위도 달라진다. 어느 모델이 함수를 더 잘 작성하는지만으로는 충분하지 않다. 작업을 얼마나 잘게 나눌지, 각 작업에 어떤 모델을 배치할지, 검증은 어디에 넣고 실패하면 어디로 되돌릴지를 함께 결정해야 한다. 내가 지금 중요하게 보는 두 가지는 그래프 엔지니어링과 소프트웨어 팩토리다.

여기서 그래프는 작업과 에이전트의 실행 그래프다. 코드나 모델 호출, 에이전트 실행이 노드가 되고, 그 결과에 따라 다음 작업으로 넘어가거나 검증과 재시도로 되돌아가는 경로가 간선이 된다. LangChain이 올해 7월 정리한 그래프 엔지니어링도 이 문제를 다룬다. 미리 정할 수 있는 절차와 에이전트의 판단을 어떻게 조합할 것인가. 재시도가 들어가므로 실행 그래프에는 순환도 생긴다.1

소프트웨어 팩토리는 이 연결을 실제 개발 과정으로 운영하려는 시도다. StrongDM은 명세와 시나리오를 입력으로 받아 에이전트가 코드를 작성하고 검증을 반복하는 비대화형 개발 사례를 공개했다. 사람이 직접 코드를 쓰거나 리뷰하지 않는다는 원칙까지 세웠다. 모든 개발 조직이 그렇게 일한다는 뜻은 아니다. 다만 사람이 구현의 매 순간을 수습하지 않는 개발이 이미 구체적인 운영 모델로 제시되고 있다.2

모델을 고르는 수단도 있다. RouteLLM은 작업 요청을 서로 다른 모델에 배분할 때 품질과 비용을 함께 고려하는 연구이고, LiteLLM 같은 기반 도구는 여러 모델에 대한 라우팅, 재시도, 폴백을 제공한다.3 테스트와 리뷰, 시나리오 검증 역시 실행 과정에 연결할 수 있다. StrongDM의 사례에서도 구현과 함께 중요한 것이 검증 환경과 피드백이었다.4

그렇게 여러 단계를 연결하고 나면, 내가 더 무게를 두게 되는 것은 안정성과 예측 가능성이다. 특히 중저가 모델까지 적극적으로 활용하려면, 프롬프트에 써 둔 지시가 매번 지켜진다는 가정 위에 다음 단계를 놓기 어렵다. 그렇다고 가격이 비싸면 해결되는 문제도 아니다. HAL 연구의 실패 분석에서도 강한 모델을 사용한 에이전트가 명시적인 지시를 어기거나, 도구 사용에 실패하고 복구하지 못하는 사례가 보고됐다.5 모델 가격에 따라 준수율을 일렬로 세우기보다, 내 작업에서 어떤 실패가 발생하고 어떻게 복구되는지 확인해야 한다.

나는 앞선 1인 개발 기록에서 제품을 완성하기 위해 만들었던 하네스를 소개했다. 테스트를 실행하고, 완료의 근거를 확인하고, 개발 규칙을 판정하는 장치들이었다. 그 경험을 다른 프로젝트에서도 쓸 수 있게 옮기면서 새로운 질문이 생겼다. 내 프로젝트의 사정을 모르는 개발자에게, 이 장치들이 지키려는 약속을 어떻게 설명할 수 있을까.

그 질문에서 시작한 도구가 Polydeukes, 폴리데우케스다.

2. 우리는 하네스라는 말로 무엇을 가리키는가

하네스는 이제 내가 에이전트에게 긴 작업을 맡길 때 당연히 준비하는 기반이다. 그런데 다른 개발자와 하네스를 이야기하기 시작하면, 같은 단어로 서로 다른 물건을 가리키고 있다는 사실을 곧 알게 된다.

어떤 사람은 상세한 프롬프트와 규칙 파일을 뜻한다. 어떤 사람은 API 수준에서 JSON 스키마를 강제하는 structured output을 떠올린다. 또 어떤 사람은 도구 실행 직전 훅을 호출해 허용 여부를 결정하는 구조를 말한다. 작업 분할과 모델 배치, 테스트와 재시도까지 포함한 실행 환경 전체를 하네스라고 부르기도 한다.

이 장치들은 서로 다른 책임을 맡는다.

장치 주로 다루는 것 별도로 확인해야 하는 것
프롬프트·규칙 파일 모델이 읽고 해석할 지침 실행 중 실제로 지켰는가
Structured output 출력이 따라야 할 구조와 형식 내용이 맞고 작업이 완결됐는가
실행 훅 특정 시점의 검사와 허용·차단 필요한 행동을 관측했으며 복구 경로가 있는가
실행 그래프 작업의 순서·분기·검증·재시도 각 단계가 어떤 약속을 전제로 하는가

가령 Claude Code 문서도 규칙 파일을 모델에 제공하는 맥락으로 설명한다. 훅은 그와 다른 실행 제어 수단이다. Structured output 역시 출력 형식을 제약하지만, 형식에 맞는 답이 곧 올바른 답이라는 뜻은 아니다.6

이 차이를 생략한 채 “우리도 하네스를 쓴다”고 말하면 대화가 쉽게 어긋난다. 조금 과장하면 바벨탑에서 흩어진 사람들 같다. 같은 탑을 짓는다고 생각했는데, 서로 무엇을 쌓고 있는지부터 다시 설명해야 한다.

나는 이 문제를 두 질문으로 나누었다. 어떻게 집행할 것인가. 그리고 어떤 약속을 판정할 것인가.

프롬프트로 알려 줄지, 훅에서 막을지는 첫 번째 질문이다. 두 파일의 키 집합이 같아야 하는지, 어떤 변경에 다른 변경이 따라와야 하는지, 다음 단계에 들어가기 전에 증거가 필요한지는 두 번째 질문이다. Polydeukes에서 먼저 이름을 붙이고 싶었던 것은 이 두 번째 질문에 반복해서 등장하는 관계들이었다.

3. 반복되는 약속에 이름을 붙이다

출발점은 회사에서 제품을 개발하며 쌓아 둔 판정 스크립트였다. 그 안에는 도메인 용어와 프로젝트의 디렉터리 구조, 당시의 작업 관행이 섞여 있었다. 스크립트를 그대로 옮기면 다른 프로젝트에서도 곧바로 쓸 수 있으리라고 기대하기 어려웠다.

그래서 프로젝트 고유의 이름을 걷어 내고, 판정이 요구하는 관계를 살폈다. 겉으로 달라 보이는 규칙들 사이에 반복되는 모양이 있었다.

한국어와 영어 번역 파일을 예로 들어 보자. 영어 파일에 settings라는 키를 추가했다면 한국어 파일에도 같은 키가 있어야 한다. 번역된 문장은 달라도 된다. 확인하려는 약속은 두 파일에서 추출한 키 집합의 일치다. 나는 이 모양에 pairing, 짝 맞춤이라는 이름을 붙였다.

어떤 코드를 바꾸면 관련 문서도 함께 바꾸어야 한다는 약속은 조금 다르다. 두 집합이 같을 필요는 없다. 한쪽의 변경이 다른 쪽의 변경을 요구한다. 이 모양은 companion, 동반 의무다. 검증의 증거가 있어야 다음 단계로 넘어갈 수 있다는 약속은 phase-order, 단계 순서로 설명할 수 있다. 실제로 판정하려면 각각 어떤 변경과 어떤 증거를 읽을 수 있는지까지 정해야 하지만, 이름을 붙이는 것만으로도 우리가 논의할 질문은 분명해진다.

이런 식으로 정리한 연구 카탈로그에는 20개 유형이 있다. 무엇끼리 맞아야 하는지를 다루는 관계, 누가 무엇을 할 수 있는지를 다루는 권한, 선행 증거를 다루는 이력, 허용하는 어휘와 이름을 다루는 형식, 변경의 방향, 예외와 처분을 다루는 정책의 여섯 묶음이다. 이 숫자는 연구 분류의 크기다. 스무 가지 기능이 모두 구현됐다는 의미는 아니다.7

여기서 빌리고 싶은 선례가 GoF의 Design Patterns다. 이 책은 반복되는 객체지향 설계를 패턴으로 정리하고, 각각의 이름과 적용 맥락, 해법과 결과를 설명했다.8 개발자들이 패턴 이름으로 대화할 수 있게 되면 설계의 의도를 전달하는 방식도 달라진다. 코드 전체를 먼저 보여 주지 않아도, 어떤 문제를 풀려는지부터 이야기할 수 있다.

하네스에도 그런 언어가 있으면 좋겠다. “이 훅 스크립트를 복사해서 쓰세요”와 함께 “이 규율은 pairing입니다. 여기서는 번역 파일 두 개에서 키를 추출합니다”라고 설명하는 것이다. 상대는 곧바로 자신의 프로젝트에서 무엇을 비교할지 생각할 수 있다. 다른 언어나 에이전트 도구를 사용하더라도, 비교하려는 관계부터 공유할 수 있다.

물론 이름만 같다고 같은 규율이 되지는 않는다. 어느 시점의 파일을 읽는지, 입력이 없으면 어떻게 처리하는지, 예외는 누가 인정할 수 있는지가 함께 따라와야 한다. 그래서 내가 생각하는 하네스 패턴은 이름표와 함께 필요한 증거, 적용 조건, 예외와 실패 사례를 설명하는 단위다. 이런 설명이 쌓여야 다른 개발자가 자신의 환경으로 옮겨 갈 수 있다.

에이전트의 규칙을 언어로 다루려는 연구는 이미 있다. AgentSpec도 트리거와 조건, 집행 방식을 명시하는 런타임 규칙 언어를 제안한다.9 그 가운데 Polydeukes가 보태고 싶은 것은 개발 관행에서 반복되는 관계의 카탈로그다. 이 분류가 다른 프로젝트에서도 통하는지, 빠진 유형은 무엇인지 검토받고 싶다. 하네스 패턴이라는 공통 언어가 자라면 도구를 만드는 사람과 사용하는 사람 사이의 대화도 훨씬 구체적이 될 것이라 기대한다.

4. 규율은 작은 언어로 쓴다

패턴의 이름은 사람끼리 대화할 때 필요하다. 실행하려면 그 약속을 기계가 판정할 수 있는 형태로 적어야 한다.

번역 키의 짝 맞춤에서는 한국어 파일과 영어 파일을 읽고, 각각에서 키를 추출한 뒤, 두 집합이 같은지 비교하면 된다. Polydeukes의 규율 선언도 이 순서를 따른다. 입력을 지정하고, 필요한 값을 추출하고, 그 사이의 관계를 적는다. 공식 예제에서 비교 부분만 꺼내면 다음과 같다.10

relate:
  - id: 'parity'
    relation: { op: 'equal', of: ['koKeys', 'enKeys'] }

koKeysenKeys를 만드는 앞부분의 추출 선언은 생략했다. pairing이 사람이 이해하는 패턴 이름이라면, 여기의 equal은 엔진이 수행하는 관계 연산이다. 한국어에는 없고 영어에만 있는 키가 있다면, 그 차이가 진단의 근거가 된다. 번역 문장의 자연스러움까지 이 식이 평가하는 것은 아니다.

현재 관계 연산은 비어 있음, 비어 있지 않음, 동등, 포함, 함의, 순서, 불변의 일곱 가지다. 이들과 추출·집합 연산을 조합해 규율을 만든다. 같은 equal도 무엇을 추출하느냐에 따라 다른 약속에 쓰일 수 있다.11

번역 키 외에도, 실제 서비스의 개발 저장소에는 다음과 같은 규율을 선언해 두었다.12

  • 공통 래퍼를 거쳐 호출하기 — added-only. 앱에서 햅틱 모듈을 직접 가져오는 코드를 새로 추가하면 접근성 규약이 호출부마다 흩어질 수 있다. 변경 전후에서 직접 import를 추출하고, 새로 생긴 항목만 판정한다. 기존 코드의 위반까지 매번 같은 경고로 쌓지 않으면서 이번 변경이 늘린 문제를 볼 수 있다.
  • 불변식 주석 보존하기 — one-way-marker. 과거 결함을 고친 이유를 INVARIANT 주석으로 남겼다면, 변경 전의 주석 집합이 변경 후에도 포함돼야 한다. 주석을 삭제하거나 문구를 바꾸면 진단이 나온다. 기록을 고치는 것 자체를 금지하려는 것이 아니라, 기존 결정을 뒤집는 변경임을 드러내려는 규율이다.
  • 테스트 작성 뒤 감사하기 — phase-order. 프로덕션 코드를 편집하기 전에 테스트 작성 에이전트와 감사 에이전트가 어떤 순서로 실행됐는지 확인한다. 이 설정은 세션 기록에서 처음 성공한 두 호출의 순서를 읽는다. 테스트의 품질이나 매번의 TDD 사이클 전체를 증명하는 것은 아니지만, 작업 절차의 선행 관계를 관측할 수 있다.

첫 번째 규율에서 새로 추가된 직접 import의 집합을 added라고 추출했다면, 관계 선언은 다음처럼 적는다. 앞의 번역 예제와 마찬가지로 추출 과정은 생략했다.

relate:
  - id: 'through-the-wrapper'
    relation: { op: 'empty', of: 'added' }

핵심은 새로 추가된 직접 호출이 없어야 한다는 약속이다. 불변식 주석에는 포함 관계를, 단계 순서에는 순서 관계를 사용한다. 규율마다 새 판정 프로그램을 작성하는 대신, 관측할 증거와 관계를 조합하는 방식이다.

이 선언 언어는 튜링 완전하지 않도록 제한했다. 규율 안에 임의의 사용자 함수를 넣거나, 루프와 재귀를 작성하는 문법을 두지 않는다. 추출 결과끼리 참조할 수 있지만 순환 참조는 미리 검사해 거부한다. 규칙 하나를 추가할 때마다 새로운 범용 프로그램을 검토해야 하는 부담을 줄이려는 선택이다.

표현력을 제한해 운영을 쉽게 만드는 접근에는 선례가 있다. CEL도 비튜링 완전성과 호스트가 제공한 데이터에 대한 접근을 설계 특성으로 삼는다.13 규칙을 쓰는 데 필요한 조합은 제공하되, 어디까지 계산하고 무엇에 접근할 수 있는지 경계를 두는 것이다.

이 제한이 Polydeukes 전체의 안전성을 증명해 주지는 않는다. 큰 입력과 복잡한 정규식의 비용, 엔진 자체의 결함은 따로 다뤄야 한다. 다만 선언식에 임의 코드를 끼워 넣거나 무한 재귀를 작성할 수 있는 경로를 없애면, 규율의 의미와 실행 범위를 검토하기 쉬워진다. 내가 원하는 표현력은 개발 과정에서 반복되는 관계를 충분히 조합할 수 있는 정도다.

그렇게 위반을 판정할 수 있게 된 뒤에도 한 가지 결정이 남는다. 약속을 어겼다는 사실을 알았을 때, 실행을 반드시 멈춰야 할까.

5. 막을 수 있어도, 먼저 관측하기로 했다

Polydeukes의 초기 설계는 차단에 더 큰 비중을 두었다. 프롬프트에 적은 부탁을 기계적인 판정으로 바꾸었으니, 어겼을 때 멈추게 해야 규율이 실효성을 갖는다고 생각하기 쉬웠다. 직접 사용하면서 그 판단을 다시 보게 됐다.

첫 도그푸딩은 Polydeukes를 만드는 에이전트에게 Polydeukes를 적용하는 방식이었다. 7월 15일 첫 작업을 마친 뒤 남은 판정 기록은 133행이었다. 차단 2행, 당시 우회로 분류한 기록 56행, 통과 75행.

숫자는 생겼지만, 차단 2건을 버그 예방 2건이라고 부를 수는 없었다. 당시 회고에는 나쁜 편집을 잡아 코드 품질을 높인 사건은 확인하지 못했다고 적었다. 그 작업의 품질에 직접 기여한 것은 TDD와 감사, 적대적 리뷰였다. 판정 기록은 오히려 보호 범위와 예외를 여는 방식에 어떤 마찰이 있는지 보여 주었다. 우회 56행에도 실제 편집뿐 아니라 예외가 열린 동안의 읽기와 중복 판정이 섞여 있었다.14

8월에는 더 묘한 장면을 기록했다. 에이전트가 코드를 작성하면서 경로 문자열을 불필요하게 나누어 이어 붙였다. 그대로 적으면 판정기가 차단할 것이라고 예상했기 때문이다. 그런데 그 예상은 틀렸다. 원래 문자열을 그대로 써도 허용되는 작업이었다.

금지된 일을 하려던 사건은 아니었다. 에이전트는 허용된 일을 더 복잡한 모양으로 수행했다. 그리고 최종 호출의 통과 기록만 읽어서는, 그 모양이 잘못 예상한 차단 때문에 생겼다는 사실을 알 수 없었다. 이 사건은 에이전트의 정직성을 재단할 근거보다, 규칙과 판정이 얼마나 이해하기 쉬운지 돌아볼 계기가 됐다.14

무인 구현을 목표로 할수록 이런 마찰은 중요하다. 실행을 막으면 그 뒤에는 이유를 이해하고, 고치고, 다시 시도하는 경로가 필요하다. 규율이 현재 작업에서 충족될 수 없거나 복구 방법이 불분명하면, 차단은 작업을 끝내지 못하는 원인이 될 수 있다. 모든 위반에 같은 처분을 내리는 설계로는 이 비용을 구별하기 어렵다.

그래서 v0.5에서 일반 규율의 기본값을 권고와 기록으로 바꾸었다. 명시적으로 차단을 선택할 수 있고, 판정 사슬 자체를 보호하는 차단도 남아 있다. 다만 새로운 규율은 우선 실행 중 어떤 결과를 내는지 관측한다. 그 결과를 보며 집행 수준을 결정한다.15

위반을 판정하는 일과 실행에 개입하는 일은 구별할 수 있다. 런타임 검증 문헌에서도 관측된 실행 흔적을 속성과 대조하는 모니터링과, 그 결과를 이용해 실행에 개입하는 확장을 나누어 설명한다.16 나 역시 판정 결과를 얻었다는 이유만으로 모든 호출을 멈출 필요는 없다고 보게 됐다.

그렇다면 권고로 바꾸기만 하면 에이전트가 알아서 고쳤을까. 첫 측정은 그런 기대를 뒷받침하지 않았다.

8월 24일부터 28일까지의 집계에서 권고 기록은 735행이었다. 그중 같은 규율과 대상이 이후 통과로 다시 관측된 것은 73행, 약 **9.9%**였다. 당시에는 이를 ‘권고 소비율’이라고 불렀다. 다만 여기서 센 것은 로그 행이다. 에이전트의 독립적인 결정 735번도 아니고, 지시를 실제로 읽은 뒤 따랐는지 측정한 준수율도 아니다. 권고 뒤의 통과가 수정 때문인지 단순 재시도 때문인지도 이 숫자만으로는 알 수 없다.17

분모를 나누어 보니 다른 질문이 생겼다. 권고의 약 95%가 편집 전에 맥락 문서를 읽도록 요구하는 규율에 몰려 있었다. 문서를 읽지 않은 상태가 유지되면 호출할 때마다 같은 권고가 쌓였다. 어떤 규율은 이후 통과가 비교적 자주 관측됐고, 다른 규율에서는 한 번도 관측되지 않았다. 전체 평균만으로는 그 차이를 설명할 수 없었다.

권고의 내용뿐 아니라 전달도 확인해야 했다. 당시 훅 전달 시험에는 메시지를 출력했지만 모델이 받지 못한 경로가 있었다. 현재 Claude Code 문서도 허용 결정의 사유와 모델에 제공하는 추가 맥락을 구별한다. permissionDecisionReason에 적는 허용 이유는 사용자에게 보이고, 모델에 맥락을 더하려면 additionalContext라는 별도 필드를 사용한다.18

기록된 메시지, 전달된 메시지, 그 뒤에 일어난 행동은 각각 확인해야 한다. 권고가 따르기 어려웠는지, 읽어야 할 자료가 너무 많았는지, 아예 전달되지 않았는지에 따라 고칠 곳이 달라진다. 이때부터 로그는 내가 만든 규율과 워크플로우 자체를 점검하는 자료가 됐다.

6. 로그를 다시 실행 그래프로 돌려보내기

이 규율은 Polydeukes 자체를 개발하는 데만 쓰고 있지 않다. 앞선 글에서 다룬 실제 서비스의 개발 저장소에도 설치해 사용하고 있다. 이곳은 Polydeukes를 만드는 저장소와 구분되는 적용 사례다.

9월 23일 확인한 이 저장소의 설치 버전은 0.8.0이고, 설정에는 규율 28개가 선언돼 있다. 그중 26개는 권고, 2개는 명시적 차단이다. 번역 키의 짝 맞춤은 앱과 관리 화면, 랜딩 페이지에 걸쳐 11개 선언으로 쓰이고 있다. 여기서는 번역이 덜 된 화면에서 폴백을 사용하는 상태도 존재하므로, 키가 다르다는 이유만으로 모든 편집을 막지 않는다. 불일치는 진단으로 남긴다. 반면 마이그레이션 산출물의 직접 편집과 순서에 관한 두 규율은 차단을 선택했다.12

9월 16일부터 23일까지 이 저장소에 남은 판정 기록은 3,492행이었다. 다만 설치 후의 동작 확인 시험도 섞여 있으므로, 이 숫자를 실제 개발 작업 3,492건으로 읽을 수는 없다. 모든 통과를 규율의 효과로 계산할 수도 없다. shell-unjudgeable로 분류된 355행에는 셸 명령의 변경 대상을 해당 계층이 알아낼 수 없어 판정을 건너뛰었다는 사유가 남아 있었다.12 기록을 통해 확인할 것은 위반뿐 아니라 어디까지 판정할 수 있었는가이기도 하다.

이 적용 사례를 바탕으로 더 해 보고 싶은 일이 실행 그래프의 개선이다. 번역 키 사례로 돌아가 보자. 영어에 추가한 키가 한국어에서 반복해서 빠진다면, pairing 규율은 그 불일치를 기록할 수 있다. 다음으로 두 파일이 어떤 작업 경로를 거쳐 만들어졌는지 살펴볼 수 있다.

처음부터 한 에이전트에는 영어 파일만, 다른 에이전트에는 한국어 파일만 맡겼다면 두 결과를 합치는 단계가 필요하다. 담당 에이전트에게 한쪽 파일만 제공했다면 입력을 준비하는 단계를 고쳐야 한다. 작업이 진행 중이라 일시적으로 키가 다른 것이라면, 어느 시점에 두 집합이 같아야 하는지부터 다시 정해야 한다.

이처럼 같은 불일치도 작업의 경계, 입력, 검사 시점에 따라 다른 문제를 가리킨다. 규율에 이름을 붙이고 관측 대상을 명시해 두면, 무엇이 반복됐는지 설명하기 쉬워진다. 그다음에는 그래프의 어느 부분을 바꿀지 논의할 수 있다.

flowchart LR
    A["작업·에이전트 그래프 설계"] --> B["규율 선언"]
    B --> C["실행과 판정 기록"]
    C --> D["위반·복구 양상 분석"]
    D --> E["작업 경계·입력·검증·모델 배치 수정"]
    E --> A

모델 배치도 이 순환에 넣을 수 있다. 특정 모델이 특정 작업에서 같은 약속을 반복해서 놓친다면, 입력을 바꾸어 다시 평가하거나 해당 작업을 다른 모델에 맡기는 실험을 할 수 있다. 중요한 것은 모델의 평판만으로 교체하는 대신, 비교하려는 작업과 실패의 조건을 정하는 일이다.

이 그림은 현재 Polydeukes에 내장된 자동 최적화 기능을 뜻하지 않는다. 지금의 로그에는 판정 시각과 규율, 대상, 결과 등이 남지만 모델이나 작업 그래프의 노드, 정식 세션 식별자가 직접 들어 있지는 않다. 모델별·단계별로 비교하려면 실행 환경의 메타데이터를 함께 기록해야 한다. 어댑터가 관측하지 못한 행동까지 로그에 남는 것도 아니다.

그럼에도 선언한 약속과 실제 실행을 대조할 자료가 생긴다는 것은 유용하다. “이 모델은 말을 잘 안 듣는다”는 인상에서, “이 입력과 작업 순서에서 이 규율이 반복해서 충족되지 않았다”는 관측으로 옮겨 갈 수 있기 때문이다. 원인을 확정하려면 추가 비교가 필요하지만, 다음에 무엇을 바꾸어 볼지는 더 구체적이 된다.

관측을 우선한다고 완료 기준까지 느슨하게 둘 이유는 없다. 모든 언어의 번역을 함께 완성하기로 한 작업이라면, 진행 중 두 파일의 키가 잠시 달라도 편집을 이어 가게 하되 완료 전에는 두 집합이 같은지 검사할 수 있다. 빠진 키가 남아 있으면 수정 단계로 돌려보낸다. 어느 차이를 허용하고 무엇을 완료 조건으로 삼을지는 작업에 맞게 정해야 한다. 테스트와 리뷰, 시나리오 검증은 최종 산출물이 그 요구를 충족하는지 계속 확인해야 한다.4

내가 원하는 운영은 이런 순환이다. 규율을 선언하고 실행을 지켜본다. 반복되는 문제를 기록에서 찾아 작업 구조를 바꾼다. 바꾼 구조에서 같은 문제가 줄었는지 다시 확인한다. 하네스도 그 평가의 대상에 포함된다.

7. 함께 쓰려는 규율

2026년 9월 23일, 이 글에서 확인한 Polydeukes 소스의 릴리스는 0.9.0 베타다. 현재의 중심은 규율을 선언하고 판정하며 기록하는 기능과, 이를 에이전트 실행 환경에 연결하는 어댑터다. 작업 장부와 기억, 별도의 검증 도구는 후속 계획에 남아 있다. 실제 서비스 개발 저장소에 적용한 기록도 생겼다. 이제 그 기록에서 무엇을 배웠고 어떤 작업 구조를 바꾸었는지, 도입이 어떤 효과를 냈는지 계속 확인하려 한다.

Polydeukes를 오픈소스로 나누며 기대하는 것은 두 가지다. 반복되는 규율을 함께 설명할 이름을 만드는 것. 그리고 그 규율이 실제로 어떤 결과를 남겼는지 살펴보며 작업 방식을 개선하는 것. 앞의 언어가 있어야 서로의 설계를 이해할 수 있고, 뒤의 기록이 있어야 그 설계를 고칠 근거가 생긴다.

좋은 사례만 모을 생각은 없다. 어떤 규율은 쓸모가 없을 수 있다. 관측 시점이 잘못됐거나, 필요한 증거를 얻을 수 없거나, 지키는 비용이 얻는 것보다 클 수도 있다. 그런 사례까지 같은 이름 아래에서 이야기할 수 있다면, 다음 개발자는 그 규칙을 가져갈지 판단하기 쉬워질 것이다. 내가 바라는 하네스 패턴의 카탈로그는 그렇게 사용 경험과 함께 고쳐지는 것이다.

폴리데우케스라는 이름은 그리스 신화에서 가져왔다. 핀다로스가 전한 이야기에서 폴리데우케스는 혼자 신들 곁에서 사는 대신 카스토르와 운명을 나누는 쪽을 선택한다. 형제는 하늘과 지하에서 보내는 시간을 나누어 갖는다.19 나는 그 이야기에서 자신이 가진 것을 나누어 계속 함께하려는 선택에 마음이 갔다.

테스트를 쓰고, 변경의 근거를 확인하고, 실패한 접근을 기록하는 일은 에이전트에게 요구하기 전부터 개발자가 자신에게 부과하던 규율이었다. 내가 어렵게 배운 작업 관행을 함께 일하는 상대에게도 건넬 수 있다. 그리고 실제로 도움이 되는지는 함께 일한 기록을 보며 다시 판단할 수 있다.

이 프로젝트에서 규율을 선물이라 부르는 이유다. 내가 아는 좋은 작업 방식을 건네되, 그것이 언제나 옳다고 가정하지 않는다. 그 약속에 이름을 붙이고, 실행에서 남긴 결과를 함께 읽고 싶다.

Footnotes

  1. 코멘트: Sydney Runkle·Harrison Chase, 3 Years of Graph Engineering with LangGraph, LangChain, 2026-07-22. 코드·모델 호출·에이전트를 노드로 조합하는 방식과 순환을 설명한다. 모든 작업을 미리 고정한 그래프로 만들어야 한다는 주장과는 구별한다.

  2. 코멘트: Justin McCarthy, Software Factories And The Agentic Moment, StrongDM, 2026-02-06. 명세와 시나리오를 바탕으로 구현·검증을 반복하는 조직 내부의 운영 사례다.

  3. 코멘트: Isaac Ong 외, RouteLLM: Learning to Route LLMs from Preference Data, 2024, 개정 2025; LiteLLM 공식 라우팅 문서. 전자는 모델 선택의 비용·품질을, 후자는 라우팅·재시도·폴백 같은 운영 수단을 다룬다. 모델 가격별 지시 준수율을 입증하는 자료로 사용하지 않았다.

  4. 코멘트: StrongDM Software Factory — Principles, 2026. 검증 환경과 피드백, 실제 사용 환경에 가까운 평가와 홀드아웃 시나리오를 강조한다. 2

  5. 코멘트: Sayash Kapoor 외, Holistic Agent Leaderboard: The Missing Infrastructure for AI Agent Evaluation, 2025, §4.2. 실패 과제의 실행 기록에서 지시 위반과 도구 오류, 복구 문제를 분석한다. 해당 분석을 전체 과제의 실패율이나 저가 모델의 준수율로 환산하지 않았다.

  6. 코멘트: Claude Code — How Claude remembers your project, Claude Code — Hooks reference, Anthropic — Structured outputs. 공식 문서, 2026-09-23 확인. 지침 제공, 실행 제어, 출력 스키마 제약의 역할을 나누어 참조했다.

  7. 코멘트: 20개는 2026-07-30에 정리한 자체 연구의 분류다. 이 글의 기준 소스에서 카탈로그는 18개 이름을 다루며, 그중 delegated-scope는 선언을 거부하는 예약 항목이다. 연구 분류의 수, 코드에 등록된 이름의 수, 실제 지원 범위는 서로 다르다.

  8. 코멘트: Erich Gamma·Richard Helm·Ralph Johnson·John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994년 출간·1995년 판권. 여기서는 반복되는 설계를 이름·맥락·해법·결과와 함께 카탈로그화하는 방식을 참조한다.

  9. 코멘트: Haoyu Wang·Christopher M. Poskitt·Jun Sun, AgentSpec: Customizable Runtime Enforcement for Safe and Reliable LLM Agents, 2025년 사전 공개, ICSE 2026. 본문 비교는 초록에 제시된 런타임 규칙 언어의 구성에 한정한다.

  10. 코멘트: Polydeukes, 규율 작성하기 — 번역 키 짝 맞춤. 본문의 YAML은 전체 예제 중 관계 선언만 발췌했다. 제품 동작에 관한 설명은 2026-09-23의 로컬 소스 커밋 529bee3을 기준으로 확인했다.

  11. 코멘트: Polydeukes, 선언 대수와 참조 그래프 검사, 선언 컴파일·실행. 일곱 관계 연산은 empty, nonEmpty, equal, subset, implies, ordered, unchanged다. 작업 실행 그래프의 재시도 순환과 규율 식에서 거부하는 순환 참조는 서로 다른 층위다.

  12. 코멘트: 별도 서비스 개발 저장소의 설정·설치 패키지·.polydeukes/roi.log를 2026-09-23 KST에 읽기 전용으로 확인했다. 로그 범위는 09-16 13:08:32부터 09-23 21:54:20까지이며, 원본 전체 3,492행은 passed 3,040, skipped 367, blocked 42, advised 32, unattributed 11로 구성된다. 28개는 현재 선언 항목 수이며 자기 보호 설정은 별도다. 기간 중 0.7.1에서 0.8.0으로 바뀐 이력이 있어 모든 행을 같은 버전의 결과로 보지 않았다. 시험용 대상도 확인됐으며, 자연 발생과 시험을 전부 분리한 성과 집계는 아니다. shell-unjudgeable 355행의 no-observation 의미는 설치된 0.8.0의 판정 코드와 대조했다. 2 3

  13. 코멘트: Common Expression Language 공식 사이트, 2026-09-23 확인. 비튜링 완전성과 호스트가 제공한 데이터로 접근을 제한하는 설계를 소개한다. CEL의 특성이 Polydeukes 구현의 안전성을 대신 증명하는 것은 아니다.

  14. 코멘트: 자체 개발 기록, 2026-07-15 첫 도그푸딩 회고 및 2026-08-02 차단 예상에 따른 문자열 조립 사례. 133은 첫 작업의 판정 로그 행 수이며, 당시 bypassed에는 예외가 열린 동안의 경로 언급과 중복 판정이 포함돼 있다. 문자열 사례는 실제 차단 없이 허용된 작업을 불필요하게 바꾼 단일 관측이다. 2

  15. 코멘트: Polydeukes, v0.5 — 진단 우선 전환, 2026-08. 일반 규율의 advise 기본값과 항목별 차단 선택을 설명한다. 이 개발 기록의 당시 전달 실험과 현재 호스트 문서의 계약은 구분해서 읽어야 한다.

  16. 코멘트: Martin Leucker·Christian Schallhart, A Brief Account of Runtime Verification, Journal of Logic and Algebraic Programming 78(5), 2009, pp. 293–303. §2에서 관측된 실행 흔적의 검증을 정의하고, §5에서 실행에 개입하는 확장을 다룬다.

  17. 코멘트: v0.5 개발 기록의 측정 절과 자체 도그푸딩 8차 집계. 기간은 2026-08-24 기본값 전환부터 08-28 관문까지다. 권고 735행 중 같은 추정 세션에서 동일한 (label, subject)가 이후 passed로 관측된 73행을 셌다. 세션은 로그 간격이 30분을 초과하면 나누는 방식으로 근사했다. 맥락 읽기 계열은 701/735행이었다. 이 지표는 권고 수신 여부나 수정의 인과관계를 입증하지 않는다.

  18. 코멘트: Claude Code — PreToolUse decision control, 공식 문서, 2026-09-23 확인. 허용 결정의 permissionDecisionReason과 모델에 공급하는 additionalContext의 수신자를 구별한다. 8월의 자체 전달 시험은 당시 확인한 경로에 대한 관측이며, 모든 권고 채널에서 전달이 불가능하다는 뜻은 아니다.

  19. 코멘트: Pindar, Nemean Ode 10, F. A. Paley 번역. 폴리데우케스가 형제와 운명을 나누기로 선택하는 후반부의 전승을 참조했다. ‘규율을 선물로 나눈다’는 뜻은 이 장면에서 가져온 나의 해석이다.

TAGS — 오픈소스 / AI / 회고

폴리데우케스 — 하네스에도 공통 언어가 필요하다 — OG 카드