클로드 코드 /goal: 목표를 달성할 때까지 에이전트 굴리기

클로드 코드 /goal: 목표를 달성할 때까지 에이전트 굴리기

클로드 코드로 큰 작업을 시키다 보면 매 턴 마지막에 “다음 단계 진행해줘”나 “계속”이라고 답하는 자기 자신을 발견하게 됩니다. 테스트가 다 통과할 때까지, 마이그레이션이 끝날 때까지, 인수 조건이 모두 충족될 때까지 분명한 종착점은 있는데 그 사이를 사람이 일일이 클릭으로 끌고 가야 하죠. 🤔

이런 패턴을 한 줄로 해결해주는 명령어가 클로드 코드의 /goal입니다. 종료 조건을 걸어두면 매 턴이 끝날 때마다 별도 모델이 “조건이 만족됐나?”를 판단하고, 아니면 Claude가 알아서 다음 턴을 시작합니다. 이번 글에서는 /goal의 사용법과 동작 원리, 그리고 /loop로 반복 실행이나 플랜 모드 같은 비슷한 도구와의 차이를 살펴보겠습니다.

/goal이 뭔가요?

/goal은 현재 세션에 종료 조건을 걸어두는 슬래시 커맨드입니다. 조건이 충족될 때까지 클로드가 스스로 다음 턴을 시작하기 때문에, 한 번 명령을 내려두면 사람이 다시 끼어들 필요 없이 작업이 끝까지 흘러갑니다.

/goal 모든 테스트가 통과하고 린트 단계가 깨끗해질 때까지

이 한 줄로 목표가 세션에 걸리고 곧바로 첫 번째 턴이 시작됩니다. 별도 프롬프트를 보낼 필요는 없고, 목표가 활성화되어 있는 동안에는 화면에 ◎ /goal active라는 표시가 떠서 얼마나 오래 돌고 있는지 알려줍니다.

요구사항이 두 가지 있습니다. 우선 클로드 코드 v2.1.139 이상이어야 합니다. 그리고 /goal이 내부적으로 Hooks 시스템을 사용하기 때문에, 설정에서 disableAllHooks나 관리 설정의 allowManagedHooksOnly가 켜져 있으면 동작하지 않고 그 이유를 알려줍니다.

기본 사용법

하나의 명령어가 세 가지 동작을 합니다. 인자가 무엇인지에 따라 설정, 상태 확인, 종료로 갈라지죠.

목표를 새로 거는 가장 단순한 형태는 /goal 뒤에 조건을 자연어로 적는 겁니다.

/goal 이번 주에 머지된 모든 PR이 CHANGELOG.md에 항목으로 들어 있을 것

이미 활성 목표가 있는 상태에서 새로 걸면 그냥 새 조건으로 교체됩니다. 굳이 먼저 해제할 필요는 없어요.

활성 상태를 들여다보고 싶을 땐 인자 없이 호출합니다.

/goal

조건 자체, 얼마나 오래 돌고 있었는지, 평가된 턴 수, 지금까지 들어간 토큰, 그리고 가장 최근에 평가자가 남긴 “왜 아직 충족되지 않았다고 보는지”의 짧은 이유가 함께 나옵니다. 이 이유 줄을 보면 Claude가 다음 턴에 뭘 할지 예측이 됩니다.

조기 종료는 clear입니다.

/goal clear

stop, off, reset, none, cancel 모두 같은 동작을 하는 별칭이에요. 어느 단어가 손에 익었든 그대로 쓸 수 있고, 대화를 통째로 새로 시작하는 /clear를 누르면 활성 목표도 함께 사라집니다.

좋은 조건 작성하기

/goal을 처음 써본 사람이 가장 자주 부딪히는 건 “조건이 너무 추상적이라 끝나지 않는” 상황입니다. 평가자는 별도 모델로 돌긴 하지만 도구를 호출하지 못합니다. 즉, 평가자가 직접 파일을 읽거나 명령어를 돌려서 확인할 수가 없고, Claude가 대화에 노출한 내용만 가지고 판단합니다. 그래서 조건을 쓸 때는 “Claude가 무엇을 보여줘야 평가자가 끝났다고 결정할 수 있는가”를 먼저 떠올리는 게 좋아요.

오래가는 조건에는 보통 세 가지가 들어 있습니다. 첫째는 측정 가능한 한 가지 종료 상태입니다. 테스트 결과, 빌드 종료 코드, 파일 개수, 빈 큐처럼 명확하게 한 번에 판가름 나는 사실이어야 해요. 둘째는 증명 방법입니다. “npm test가 종료 코드 0으로 끝난다”나 “git status가 비어 있다”처럼 Claude가 어떤 명령을 돌려서 결과를 대화에 남겨야 하는지를 함께 적습니다. 셋째는 유지해야 할 제약입니다. 가는 길에 다른 테스트 파일을 건드리지 말라거나, 특정 디렉토리는 건드리지 말라는 식의 가드레일이죠.

여기에 한 가지 더 추가하면 좋은 게 상한선입니다. 조건이 영영 충족되지 않을 가능성이 있으면 자동 반복이 한없이 돌 수 있으니까요. 조건 안에 “또는 20턴 후에 멈춰”처럼 턴이나 시간 제한을 같이 적어두면, Claude가 매 턴 그 절에 맞춰 진행 상황을 보고하고 평가자도 이 부분을 함께 판단합니다.

예를 들어 마이그레이션 작업에 거는 조건은 이런 모양이 됩니다.

/goal src/api 아래 모든 호출부를 v1에서 v2로 마이그레이션. `bun test`가
종료 코드 0으로 끝나고 `bun tsc --noEmit`이 깨끗할 때까지 계속할 것.
src/legacy 아래 파일은 절대 수정하지 말 것. 25턴 안에 못 끝내면 중단.

조건 문자열은 최대 4,000자까지 받습니다. 한 줄에 끼워 넣기 어려운 복잡한 인수 조건이라면 여러 줄에 걸쳐 또박또박 적어도 무방합니다.

동작 원리

/goal은 사실 새로운 엔진이 아니라 Hooks 시스템 안에 이미 있던 프롬프트 기반 Stop hook의 세션 스코프 래퍼입니다. 즉, 매 턴이 끝날 때마다 hook이 발동되고, 그 hook이 별도 모델에게 “조건을 만족했나?”를 물어보는 구조죠.

질문을 받는 모델은 세션 설정의 small fast model입니다. 기본값은 Haiku 계열이고, 평가용 호출이라 토큰 사용량이 메인 턴에 비해 거의 무시할 만한 수준입니다. 평가자는 yes/no와 짧은 이유 한 줄을 돌려줍니다. “no”면 그 이유가 다음 턴을 시작하는 Claude에게 가이드로 함께 전달되고, “yes”면 목표가 자동으로 해제되며 트랜스크립트에 “달성됨” 기록이 남습니다.

여기서 중요한 디자인 결정이 있습니다. 평가자는 작업을 수행한 Claude와 다른 인스턴스라는 점이에요. 같은 모델이 자기 결과를 자기가 판단하면 “충분히 됐다고 봐”라고 우길 여지가 생기는데, 별개의 새 모델이 대화 기록만 보고 판단하니까 그 편향이 줄어듭니다. 다만 평가자가 도구를 못 쓴다는 한계는 이 분리의 대가입니다. 결국 “Claude가 대화에 무엇을 노출했는가”가 평가의 전부라, 좋은 조건 작성이 그토록 중요한 거죠.

/loop, ralph-wiggum과의 차이

코딩 에이전트를 자동으로 끝까지 굴리는 방법이 클로드 코드 안팎에 여럿 있어서 처음에는 헷갈리기 쉽습니다. 셋을 한 문장씩만 놓고 보면, /goal은 매 턴 끝에서 평가자가 조건을 따져 다음 턴을 깨우고, /loop는 시계가 정해진 간격마다 깨우고, ralph-wiggum은 외부 셸 스크립트가 매번 새 세션을 띄웁니다.

/goal/loop의 핵심 차이는 시계가 깨우느냐 조건이 깨우느냐예요. “5분마다 PR 큐를 살펴봐”는 /loop의 영역이고, “테스트가 다 통과할 때까지 돌려”는 /goal의 영역입니다. 정확히는 /goal이 내장 슬래시 커맨드, /loop는 내장 스킬이라 출신이 다른데, 슬래시로 호출하는 사용자 입장에서는 같은 결의 도구로 다뤄도 무방합니다.

ralph-wiggum과의 차이는 더 본질적입니다. ralph는 같은 프롬프트로 클로드 코드 세션을 처음부터 다시 띄우는 외부 셸 루프이고, /goal은 같은 대화 안에서 다음 턴을 이어가는 내부 평가 루프입니다. 그래서 ralph는 매번 빈 컨텍스트로 시작하는 만큼 “지금까지의 진행 상황”을 SPEC.md 같은 파일에 명시적으로 적어둬야 다음 반복이 의미를 가집니다. 반면 /goal은 한 대화가 끝까지 흘러가므로 이전 턴의 도구 호출 결과나 결정이 자연스럽게 누적됩니다. “단순한 셸 루프 + 똑똑한 LLM”이 ralph라면, /goal은 “똑똑한 종료 판단 + 똑똑한 LLM”인 셈이죠.

세션을 아예 백그라운드로 보내서 다른 일을 하면서 진척을 확인하고 싶다면 agents view와도 조합할 수 있습니다. /goal을 걸어둔 세션을 /bg로 백그라운드에 넣으면 평가자가 계속 돌면서 조건 충족까지 알아서 일하고, 사람은 다른 세션을 들여다보고 있으면 됩니다.

비대화 모드와 세션 재개

/goal비대화(headless) 모드에서도 동작합니다. -p 플래그로 한 번에 실행하면 조건이 충족될 때까지 루프를 돌고 종료해요.

claude -p "/goal 이번 주에 머지된 모든 PR이 CHANGELOG.md에 항목으로 들어 있을 것"

CI에서 한밤중에 돌리거나 cron으로 새벽 트리아지를 시키는 식의 사용에 잘 맞습니다. 중간에 끊고 싶으면 평소처럼 Ctrl+C로 프로세스를 멈추면 됩니다.

세션을 도중에 닫았더라도 --resume이나 --continue로 되살리면 활성 상태였던 목표가 함께 복원됩니다. 다만 조건만 그대로 이어지고, 경과 시간, 턴 수, 토큰 사용량 같은 측정값은 재개 시점에 0으로 리셋됩니다. 이미 달성되었거나 명시적으로 해제했던 목표는 복원되지 않고요.

한도와 주의 사항

/goal은 자동 반복이라 강력한 만큼 조심할 부분도 있습니다.

가장 중요한 건 조건이 영영 충족되지 않는 시나리오입니다. 평가자가 도구를 쓰지 못하므로, Claude가 어떤 이유로 결정적 결과를 대화에 노출하지 못하면 평가자는 계속 “no”를 돌려보냅니다. 그래서 조건에 항상 턴 상한이나 시간 상한을 함께 넣어두는 습관이 안전합니다. “또는 20턴 후 멈춰” 한 문장이면 폭주를 막아줍니다.

평가용 모델 호출은 메인 턴에 비해 토큰 비용이 거의 들지 않습니다. 다만 메인 턴 자체가 자동으로 반복되니까 사용량은 결국 턴 수에 비례합니다. 활성 상태에서 /goal을 인자 없이 호출하면 누적 토큰을 그때그때 확인할 수 있고, 폭주가 의심되면 즉시 /goal clear로 멈출 수 있어요.

설정 측면에서는 hook 시스템에 묶여 있다는 점이 영향을 줍니다. 워크스페이스 신뢰 대화를 수락하지 않은 디렉토리에서는 동작하지 않고, 조직 정책으로 hook을 비활성화한 환경에서도 마찬가지입니다. 이런 경우 명령어가 침묵하지 않고 왜 안 되는지 메시지를 띄우니, 메시지대로 신뢰 설정이나 hook 설정을 살펴보면 됩니다.

마지막으로 한 세션에는 목표 한 개만 활성화됩니다. 여러 조건을 동시에 추적하고 싶다면 세션을 여러 개 띄우고 agents view에서 관제하는 게 자연스럽습니다.

마치며

/goal은 “끝까지 가야 끝나는 작업”에 사람이 매 턴 끼어드는 비용을 없애주는 작은 명령어입니다. 핵심은 좋은 조건을 쓰는 거예요. 측정 가능한 종료 상태, Claude가 그걸 어떻게 증명할지, 가는 길에 무엇이 바뀌면 안 되는지, 그리고 영영 못 끝낼 경우의 안전 상한선. 이 네 가지를 한 줄에 담는 연습을 몇 번 하면 마이그레이션부터 인수 조건 충족까지 다양한 작업이 한 명령어로 흘러갑니다.

처음 써본다면 작은 작업부터 시작해보는 걸 추천해요. “특정 파일에서 lint 경고를 0으로, 또는 10턴 후 멈춰” 정도면 부담 없이 동작을 체감할 수 있습니다. 익숙해진 뒤에 마이그레이션이나 백로그 정리 같은 큰 작업으로 옮겨가도 늦지 않습니다. 더 정교한 검증 로직이 필요해진다면 그때 Hooks로 직접 Stop hook을 짜는 단계로 자연스럽게 넘어가게 되고요.

더 자세한 내용은 Keep Claude working toward a goal 공식 문서를 참고하세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord