시작하며
superpowers, gstack, omc, omo 등 많은 하네스 도구가 나오고 있습니다. 하지만 대부분 누구에게나 잘 맞도록 설계된 범용 하네스 도구입니다.
좋은 도구들이지만 회사 업무에서는 프로젝트마다 코드 구조, 검증 기준, 작업 흐름, 팀의 암묵지가 다릅니다. 이런 프로젝트별 맥락은 범용 하네스만으로 충분히 반영하기 어렵습니다.
결국 하네스는 가져다 쓰는 도구에서 끝나지 않고, 나와 회사의 코드베이스와 작업 방식에 맞게 계속 다듬어야 하는 엔지니어링 대상이 되어야 합니다.
맞춤형 하네스 설계는 어떻게 해야 할까?
프로젝트에 맞는 컨벤션, 아키텍처, 검증 기준을 문서로 정리하는 것만으로도 하네스 엔지니어링의 출발점이 됩니다. 실제 업무에서 암묵지로 남아 있던 기준을 줄여나가는 것만으로도 에이전트가 일하기 좋은 환경을 만들 수 있습니다.
반대로 프로젝트 컨벤션이나 아키텍처 문서가 없다면 에이전트는 매번 코드베이스를 추론해서 작업해야 합니다. 이 경우 코드 스타일이 일관되지 않거나, 기존 아키텍처를 해치는 구현이 나올 가능성이 높아집니다.
다만 모든 구조를 세세하게 설명할 필요는 없습니다. 모델 성능이 좋아지면서 에이전트는 코드베이스의 많은 부분을 스스로 파악할 수 있게 됐고, 앞으로는 그 범위가 더 넓어질 것입니다.
따라서 하네스는 지속적으로 개선을 해야하며 모델이 잘 처리하는 부분은 덜어내고 자주 놓치거나 실수하는 부분만 남기는 방향으로 발전해야 한다고 생각합니다.
하네스 엔지니어링의 핵심은 두 가지라고 생각합니다.
- 에이전트가 같은 실수를 반복하지 않도록 피드백 루프를 구성하는 것
- AI가 업무를 끝까지 안정적으로 해낼 수 있게 환경을 설계하는 것
반복되는 실수는 문서에 반영하면서 점진적으로 줄여갈 수 있습니다. 하지만 문서만으로는 workflow를 강제하거나, 피드백 루프를 안정적으로 구성하기 어려웠습니다.
코딩 에이전트는 대부분 요구사항 분석 -> 컨텍스트 수집 -> 계획 수립 -> 실행 -> 검증 과 같은 동작 흐름을 가집니다. 하지만 모든 상황에서 이 workflow를 그대로 따르지는 않습니다.
예를 들어 에이전트가 계획 수립이 필요 없다고 판단하면 계획 단계를 건너뛸 수 있고, 검증이 필요 없다고 판단하면 검증을 수행하지 않을 수도 있습니다.
workflow를 AI의 판단에만 의존하지 않고 워크플로가 항상 정해진 순서대로 실행되도록 강제하며, 프로젝트 상황에 맞게 점진적으로 개선할 수 있는 하네스 환경과 피드백 루프를 제공하기 위해 Phaseharness를 만들게 됐습니다.
1. Phaseharness 시작은 간단하게
시작은 단순한 스킬 기반 파이프라인이었습니다.
기본 흐름은 코딩 에이전트가 일반적으로 수행하는 작업 흐름을 스킬에 명시하고, 각 단계가 정해진 산출물을 남기도록 한 것이었습니다.
clarify -> context -> plan -> generate -> evaluateclarify -> context -> plan -> generate -> evaluate- clarify : 요구사항 정리 및 명확화
- context: 요구사항을 구현하는 데 필요한 저장소 구조, 기존 패턴, 제약사항을 조사
- plan: 기능별로 구현 단위를 나눔
- generate: 실제 구현을 수행
- evaluate: 결과를 검증
harness 스킬은 전체 workflow를 어떤 순서로 진행해야 하는지 안내하는 오케스트레이터 역할을 했습니다. 각 단계에서는 clarify.md, context.md 등에 정의된 prompt를 따라 작업을 수행했고, 결과는 .harness/artifacts 아래에 산출물로 남겼습니다.
또한 Agent Skills를 통해 Claude와 Codex CLI를 모두 지원할 수 있도록 했고, 단계별 산출물과 task 상태파일 관리를 위해 스크립트를 작성했습니다.
장점
- 복잡한 설정 없이도
clarify -> context -> plan -> generate -> evaluate흐름을 빠르게 시작할 수 있었습니다. - 파일 기반으로 단계별 산출물을 관리했기 때문에 컨텍스트가 유실돼도 artifacts 아래의 파일을 통해 결과를 확인할 수 있었습니다.
- agent skills 기반으로 정의했기 때문에, Claude와 Codex CLI 에서 같은 workflow 구조를 쉽게 적용할 수 있었습니다.
단점
- workflow를 "안내"할 뿐, 실제로 강제하지는 않았습니다. 반드시
clarify -> ... -> evaluate로 동작한다는 보장이 없었습니다. - 모든 단계가 하나의 컨텍스트에서 동작했기 때문에, 이전 단계의 내용과 구현 세부사항이 섞여서 컨텍스트가 무거워지고 에이전트의 판단이 흐려질 수 있었습니다.
2. 단일 Skill 파이프라인에서 스크립트 기반 workflow runner로
초기 구조는 단계별 산출물을 파일로 남긴다는 점에서는 효과가 있었지만, workflow 실행 자체를 강제하지는 못했습니다. 그래서 다음 단계에서는 agent가 각 단계를 직접 이어가는 방식이 아니라, 스크립트가 정해진 순서대로 workflow를 실행하도록 구조를 바꿨습니다.
run-workflow.py 스크립트를 통해 clarify, context, plan, generate, evaluate 단계를 실행하고, 각 단계의 결과를 tasks/<task-dir>/artifacts 아래에 남기도록 했습니다.
이 구조에서 현재 대화형 세션은 모든 단계를 직접 수행하지 않았습니다. 현재 세션은 runner를 실행하고 결과를 모니터링하는 얇은 오케스트레이터 역할을 했고, 실제 단계 실행은 runner가 별도의 headless agent session을 띄워 수행했습니다.
내부적으로는 단계별 실행을 analysis, build, evaluate 세션으로 나눴습니다.
analysis:clarify,context,plan을 수행하고 phase 파일을 생성build: 계획된 phase 파일을 읽고 실제 구현을 수행evaluate: 구현 결과를 독립적으로 검증
대략적인 실행 흐름은 아래와 같았습니다.
main session
-> phaseharness skill 실행 (run-workflow.py 트리거)
-> analysis headless agent session
-> build headless agent session
-> evaluate headless agent sessionmain session
-> phaseharness skill 실행 (run-workflow.py 트리거)
-> analysis headless agent session
-> build headless agent session
-> evaluate headless agent sessionrun-workflow.py는 각 session에 필요한 prompt와 artifact 경로를 전달하고, session이 끝나면 산출물이 실제로 생성됐는지 확인했습니다. 필요한 파일이 없거나 session이 실패하면 재시도 횟수 안에서 다시 실행했고, 최종 결과는 tasks/<task-dir>/index.json과 artifacts 아래에 기록했습니다.
장점
- script가
analysis -> build -> evaluate순서를 강제해 agent가 단계를 건너뛰는 문제를 줄일 수 있었습니다. - 단계별 재시도와 timeout을 script에서 관리할 수 있었습니다.
- 각 단계를 별도 agent session에서 실행해 필요한 컨텍스트만 전달할 수 있었습니다.
- 구현 session과 검증 session을 분리해 결과를 더 독립적으로 검증할 수 있었습니다.
단점
- workflow가 script 안에 고정되어 자연어로 흐름을 제어하기 어려웠습니다.
- headless session 안에서 진행되어 main session에서 현재 상태를 파악하기 어려웠습니다.
- Codex/Claude CLI 실행, prompt 구성, retry, timeout, 상태 업데이트를 직접 관리해야 해서 유지보수가 어려웠습니다.
3. Subagent와 Stop hook으로 만드는 workflow 루프
script로 workflow를 관리하면 실행 흐름을 세밀하게 제어할 수 있었습니다. 하지만 실행 책임이 script에 몰리면서 workflow를 강제하고 피드백 루프를 만들기 위한 구조로는 다소 과하다는 생각이 들었습니다.
Codex나 Claude 같은 코딩 에이전트는 이미 컨텍스트를 분리해 작업할 수 있는 subagent 기능과 에이전트의 실행 흐름에 개입할 수 있는 hook 기능을 제공합니다.
subagent와 hook을 적극적으로 활용해 하나의 session 안에서 workflow가 이어지도록 했습니다.
핵심은 두 가지였습니다.
- Stop hook: 한 단계가 끝났을 때 다음 continuation prompt를 주입하는 트리거
- subagent: 구현이나 검증처럼 독립적인 작업을 분리해서 수행하는 실행 단위
이 구조에서 Stop hook은 workflow를 직접 실행하지 않습니다. Stop hook은 현재 run 상태를 확인하고 다음 단계에서 실행할 prompt를 main session에 다시 전달하는 역할만 합니다. 실제 작업은 현재 대화형 agent가 이어서 수행합니다.
main session
-> phaseharness skill 실행
-> 현재 stage 수행
-> artifact 작성
-> run.json 상태 업데이트
-> stop
Stop hook
-> phaseharness-state.py next 호출
-> 다음 continuation prompt 주입
main session
-> 다음 stage 수행main session
-> phaseharness skill 실행
-> 현재 stage 수행
-> artifact 작성
-> run.json 상태 업데이트
-> stop
Stop hook
-> phaseharness-state.py next 호출
-> 다음 continuation prompt 주입
main session
-> 다음 stage 수행또한 각 단계에서 subagent를 활용했습니다. main session은 오케스트레이터로 남아 상태 파일과 artifact(각 단계별 산출물)를 관리하고 subagent는 주어진 phase 구현과 검증 작업을 수행합니다.
이전 구조에서는 script가 agent session을 직접 실행하는 주체였습니다. 반면 새로운 구조에서는 agent runtime이 제공하는 Stop hook과 상태 파일을 활용해 workflow를 이어갑니다.
장점
- 현재 대화형 session이 오케스트레이터로 남아 있어 사용자가 자연어로 중간에 개입하기 쉬워졌습니다.
- Stop hook은 다음 prompt를 주입하는 역할만 하므로 script runner보다 실행 책임이 가벼워졌습니다.
- 구현과 검증은 subagent로 분리하면서도 최종 상태 갱신은 main session이 관리할 수 있게 됐습니다.
단점
- subagent로 각 단계를 관리하게 되니 agent skill과 달리 Claude와 Codex의 커스텀 subagent 구성 스펙 차이를 그대로 다뤄야 했습니다. Phaseharness 프로젝트에선
.phaseharness를 SSOT로 두고 skills와 agent 정의를sync-bridge로 Codex와 Claude 스펙에 맞게 변환했지만, 결국 provider 별 차이를 위한 계층을 관리해야 했습니다. - 실무에서는 작은 단위의 요청도 많기 때문에 매번 전체 workflow를 실행해야 하는 구조는 Phaseharness를 점점 덜 쓰게 만들 가능성이 있었습니다.
- subagent 중심으로 workflow를 구성하면 특정 단계만 독립적으로 실행하기 어렵다는 문제도 있었습니다. 이를 해결하기 위해 subagent를 호출하는 별도 skill을 만들 수도 있었지만, 관리포인트가 늘어나는 단점이 있었습니다.
4. Skill 중심의 Phaseharness 구조
여러 구조를 거치며 Phaseharness의 기준은 점점 명확해졌습니다.
- workflow를 강제하려면 상태 파일과 Stop hook이 필요했습니다.
- 컨텍스트를 분리하려면 subagent가 필요했습니다.
하지만, workflow 단위를 provider별 subagent 파일로 관리하는 것은 너무 비효율적이고 개별적으로 호출하기에 어려운 구조였습니다.
최종적으로 모든 단계를 skill 로 작성하게 됐습니다.
clarify, context-gather, plan, generate, evaluate 는 모두 독립적인 skill입니다. 각 skill은 하나의 단계를 수행하고 필요한 산출물을 남기고 상태 파일을 업데이트합니다.
.phaseharness/skills/
phaseharness/
clarify/
context-gather/
plan/
generate/
evaluate/.phaseharness/skills/
phaseharness/
clarify/
context-gather/
plan/
generate/
evaluate/phaseharness skill은 전체 workflow를 실행하는 진입점입니다.
main session은 clarify, context-gather, plan 단계를 직접 수행하고 전체 workflow의 오케스트레이션을 담당합니다.
generate와 evaluate 단계에선 skill 안에 subagent를 어떤 역할로 호출을 할지 정의하고 필요한 시점에 subagent를 호출합니다.
즉, 파일 기반으로 subagent를 미리 선언해 두는 방식이 아닌 skill이 실행 중 필요한 순간에 subagent를 on-demand로 오케스트레이션 하는 구조입니다.
clarify, context-gather , plan, evaluate skill은 필요할 때 단독으로 실행할 수 있습니다. 작은 작업에 매번 전체 workflow를 태우지 않아도 됩니다.
단, generate는 plan 단계에서 생성된 phase 산출물이 있어야 실행할 수 있습니다.
generate를 단독으로 사용하는 경우는 보통 작은 작업이고 별도 context를 분리할 만큼 크지 않다고 생각해서 subagent를 사용하지 않고 main session에서 직접 수행하도록 했습니다.
반면 evaluate는 단독으로 실행해도 항상 subagent에서 수행합니다. agent가 자기 결과물을 직접 평가하면 긍정적으로 판단할 가능성이 크기 때문에 의도적으로 별도 context에서 실행하도록 했습니다.
이 구조로 바꾸면서 workflow의 기준은 skill로 단순화하고 컨텍스트 분리는 필요한 단계에서만 subagent로 처리할 수 있게 됐습니다. provider별 subagent 파일을 따로 관리하지 않아도 되고 전체 workflow와 개별 단계 실행을 같은 skill 구조 안에서 다룰 수 있습니다.
5. Phaseharness 사용법
Phaseharness의 사용 흐름은 크게 두 가지입니다.
- 큰 작업은
phaseharnessskill로 전체 workflow를 실행합니다. - 작은 작업은 필요한 skill만 단독으로 실행합니다.
전체 작업을 처음부터 끝까지 맡기고 싶다면 phaseharness를 사용합니다.
Use `phaseharness` to implement <task>.Use `phaseharness` to implement <task>.실행을 시작하면 먼저 두 가지 옵션을 확인합니다.
loop count:evaluate에서 문제가 발견됐을 때generate -> evaluate를 다시 시도할 수 있는 최대 횟수입니다.commit mode: workflow 중 commit을 진행할지 정하는 옵션입니다.
기본값은 아래와 같습니다.
loop count: 2
commit mode: noneloop count: 2
commit mode: nonecommit mode는 다음 중 하나를 선택할 수 있습니다.
none: commit을 요청하지 않습니다.phase: 각 generate phase가 끝날 때마다 commit을 요청합니다.final:evaluate가 통과하거나 경고만 남았을 때 마지막에 한 번 commit을 요청합니다.
이 경우 Phaseharness는 상태 파일을 만들고 아래 흐름을 순서대로 실행합니다.
clarify -> context-gather -> plan -> generate -> evaluateclarify -> context-gather -> plan -> generate -> evaluate작업이 진행되는 동안 각 단계의 결과는 .phaseharness/runs/<run-id>/artifacts 아래에 산출물로 남고 현재 상태는 .phaseharness/runs/<run-id>/run.json에 기록됩니다. 한 단계가 끝나면 Stop hook이 상태 파일을 확인하고 다음 continuation prompt를 주입해 workflow를 이어갑니다.
작은 작업에서는 전체 workflow를 실행하지 않아도 됩니다. 필요한 단계만 직접 호출할 수 있습니다.
Use `clarify` for <task>.
Use `context-gather` for <task>.
Use `plan` for <task>.
Use `evaluate` for the current diff.Use `clarify` for <task>.
Use `context-gather` for <task>.
Use `plan` for <task>.
Use `evaluate` for the current diff.예를 들어 요구사항과 범위만 먼저 정리하고 싶으면 clarify를 사용할 수 있습니다. 구현 전에 관련 코드와 문서를 조사하고 싶으면 context-gather만 실행할 수 있습니다. 이미 구현된 변경사항을 검증하고 싶으면 evaluate만 실행할 수 있습니다.
개별 skill을 직접 실행하면 요청한 단계만 수행하고 멈춥니다. 즉 작은 작업에 매번 전체 workflow를 태우지 않아도 됩니다.
generate는 조금 다르게 동작합니다. 전체 workflow 안에서는 plan이 만든 phase 파일을 기준으로 구현을 수행합니다. 단독으로 사용할 때도 임의의 구현 요청을 처리하는 용도가 아니라 이미 존재하는 특정 phase를 구현하는 용도로 사용합니다.
Use `generate` for phase-001.Use `generate` for phase-001.정리하면 다음과 같습니다.
| 사용 방식 | 언제 쓰나 | 동작 |
|---|---|---|
phaseharness | 큰 작업을 처음부터 끝까지 맡길 때 | 전체 workflow 실행 |
clarify | 요구사항과 범위를 먼저 정리할 때 | 목표, 범위, 성공 기준 정리 |
context-gather | 구현 전 코드 구조와 제약을 조사할 때 | 관련 코드와 문서 context 수집 |
plan | 구현 단위를 나누고 싶을 때 | phase 산출물 생성 |
generate | 계획된 phase를 구현할 때 | phase 기준 구현 |
evaluate | 변경사항을 검증하고 싶을 때 | 별도 context에서 검증 |
프로젝트 지침 연결하기
Phaseharness는 프로젝트별 지침 문서를 .phaseharness/context.json에 연결할 수 있습니다. 아키텍처 문서, 코딩 컨벤션, 리뷰 기준, 테스트 방법처럼 지침 문서를 등록해두면 context-gather와 evaluate 단계에서 해당 문서를 참고합니다.
구현 계획에 영향을 주는 문서는 context-gather.documents에 넣고, 검증 기준으로 사용할 문서는 evaluate.documents에 넣습니다. 이렇게 하면 프로젝트마다 다른 기준을 하네스에 주입할 수 있고, 에이전트가 매번 코드베이스를 처음부터 추론하지 않아도 됩니다.
실행 결과 확인하기
Phaseharness 실행 결과는 .phaseharness/runs/<run-id>/ 아래에 남습니다.
주요 파일은 다음과 같습니다.
run.json: 현재 workflow 상태, 현재 단계, loop count, generate phase 상태를 기록합니다.artifacts/clarify.md: 요구사항, 범위, 성공 기준을 정리한 결과입니다.artifacts/context.md: 참고한 코드, 문서, 제약사항을 정리한 결과입니다.artifacts/plan.md: 구현 계획과 phase 분리 결과입니다.artifacts/generate.md: 구현 단계의 결과입니다.artifacts/evaluate.md: 검증 결과입니다.phases/:plan단계에서 생성한 구현 단위 파일입니다.
작업이 어디까지 진행됐는지 확인하고 싶다면 run.json과 artifacts를 보면 됩니다.
중요: 점진적 개선
결과물이 프로젝트의 지침대로 충분히 반영하지 못했을 경우 먼저 artifacts/context.md를 확인합니다.
context.md 에는 에이전트가 어떤 문서를 읽었고 어떤 규칙과 제약을 작업에 반영했는지가 남습니다.
필요한 문서를 읽지 않았다면 .phaseharness/context.json 에 문서를 추가하거나 description을 수정합니다.
만약, context.md 에서 필요한 문서를 잘 읽었는데도 결과가 애매하다면, clarify 와 plan 단계의 산출물을 확인합니다.
clarify 에서 요구사항을 잘못 해석했는지 또는 plan 에서 phase를 너무 크게 나누어 구현 단계에서 context가 흐려졌는지 확인합니다.
검증 기준이 부족했다면 evaluate skill이나 검증 기준 문서를 보완합니다.
이 과정을 반복하며 프로젝트 지침과 Phaseharness workflow를 점진적으로 개선하고 점차 프로젝트에 특화된 하네스를 만들어 나갑니다.
자동 진행 방식
Phaseharness는 한 단계가 끝날 때마다 Stop hook을 통해 다음 단계를 이어갑니다.
Stop hook은 작업을 직접 수행하지 않습니다. 현재 상태 파일을 확인하고 다음 단계에서 실행할 prompt를 에이전트에게 다시 전달하는 역할만 합니다.
일반 대화에서는 자동으로 workflow가 시작되지 않습니다. phaseharness로 시작한 active run이 있고 현재 세션과 연결된 경우에만 다음 단계가 이어집니다.
이어서 작업하거나 병렬 실행하기
- 의도치 않게 세션이 종료된 경우 같은 프로젝트 폴더에서 새 세션을 열고
phaseharnessskill을 실행하면 기존 작업을 이어갈 수 있습니다. 진행 중인 작업이 발견되면resume을 선택합니다. - 현재 작업과 새 작업을 병렬로 진행하고 싶다면 새 세션에서
phaseharnessskill을 실행한 뒤start-new-in-worktree를 선택합니다. 그러면 Phaseharness가 새 git worktree를 만들고, 두 작업이 섞이지 않도록 분리해 진행합니다.
마치며
아무리 잘 만든 하네스라도 한 번 만들어두고 방치하면 금방 무용지물이 됩니다. LLM의 결과는 본질적으로 비결정적이기 때문에 항상 원하는 결과가 나온다고 기대하기보다 원하는 결과가 나올 확률을 계속 높여가는 방식으로 접근해야 합니다.
그 확률을 높이는 방법은 반복되는 실패를 하네스에 반영하는 것입니다. 에이전트가 필요한 문서를 읽지 않았다면 context 설정을 보완하고, 요구사항을 자주 잘못 해석한다면 clarify 단계를 고치고, 검증이 약하다면 evaluate 기준을 강화해야 합니다.
이 과정은 팀이 함께 개선할 때 더 효과적이라고 생각합니다. 작업 중 발견한 암묵지, 리뷰에서 반복되는 지적, 자주 놓치는 검증 기준을 문서와 skill에 반영하면 하네스는 점점 팀의 작업 방식에 가까워집니다.
Phaseharness는 해당 저장소에서 확인할 수 있습니다. 사용하고 싶은 프로젝트를 열고 에이전트에게 아래 텍스트만 전달하면 바로 시작할 수 있습니다.
Install phaseharness from this installer document: https://github.com/Ssoon-m/phaseharness/blob/main/installer/install-harness.mdInstall phaseharness from this installer document: https://github.com/Ssoon-m/phaseharness/blob/main/installer/install-harness.md
번외: 좋은 하네스는 점점 가벼워져야 한다.
개인적으로는 프로젝트가 성숙해질수록 하네스를 위한 문서나 구조를 조금씩 덜어내는 방향이 좋다고 생각합니다.
모든 규칙을 문서에 계속 쌓아두기보다 프로젝트 자체의 구조가 의도를 설명하고 테스트 코드로 기능의 동작을 설명하는 상태가 더 바람직합니다.
하네스는 부족한 맥락을 보완하고 반복되는 실수를 줄이기 위한 장치입니다.
모델이 코드와 테스트만으로 충분히 판단할 수 있는 부분은 점차 덜어내고 자주 놓치거나 프로젝트 특성상 중요한 기준만 하네스에 남기는 방향이 지향해야 할 방향이라고 생각합니다.
