huma — 엔드포인트 하나도 빠뜨리지 않는 래칫 Image: AI generated

15번째 엔드포인트에서 멈추는 에이전트

AI 에이전트에게 SaaS 백엔드의 Hurl 테스트를 작성하라고 시킨다. 42개 엔드포인트가 있다.

처음 10개는 순조롭다. 로그인, 회원가입, 목록 조회 — 패턴이 비슷하니까 빠르다. 15개쯤 되면 에이전트가 말한다.

“나머지 엔드포인트도 유사한 패턴이므로 완료했습니다.”

실제로 테스트가 있는 엔드포인트: 15개. 나머지 27개: 없음.

에이전트가 게으른 게 아니다. Cemri et al.이 7개 멀티 에이전트 프레임워크를 분석한 결과, 41%에서 86.7%의 작업이 실패했으며, “premature termination” — 조기 종료 — 이 14개 실패 모드 중 하나로 식별되었다 (Cemri et al., NeurIPS 2025). LLM은 생성에 최적화되어 있지, 진행률 추적에는 최적화되어 있지 않다. 어떤 엔드포인트에 테스트가 있고 어떤 엔드포인트에 없는지를 기억하지 못한다. “비슷한 패턴"이라는 판단이 남은 27개를 스킵할 근거가 되어버린다.

더 큰 모델을 쓰면 해결되는가? 20개까지 갈 수도 있다. 그래도 42개에는 도달하지 않는다. 문제는 모델의 크기가 아니라, 완료 여부를 에이전트 스스로가 판단한다는 구조에 있다.


래칫이 필요한 이유

Ratchet Pattern의 핵심은 단순하다. 완료 판정을 에이전트에게서 빼앗는다.

기계적 verifier가 “이것은 아직 안 끝났다"와 “이것은 끝났다"를 판정한다. 에이전트는 verifier가 통과시킬 때까지 작업하고, 통과되면 다음으로 넘어간다. 역주행은 불가능하다. 한 번 통과한 것은 영원히 통과다.

huma는 이 패턴을 Hurl API 테스트에 적용한 도구다. 엔드포인트 목록을 입력하면 래칫 세션을 만들고, 에이전트가 한 개씩 테스트를 작성하고 통과시키도록 강제한다. 42개가 있으면 42개 전부. Kim et al.이 10개 SOTA 도구를 20개 실서비스에 적용한 결과, 모든 도구가 낮은 커버리지를 달성했으며 “엔드포인트 간 의존성을 해결하는 것이 효과적인 API 테스트의 핵심"이라 결론지었다 (Kim et al., ISSTA 2022). huma의 순차 래칫은 이 문제를 구조적으로 해결한다.

Hurl Master — 이름 그대로다.


명령어

huma의 인터페이스는 여섯 개다.

명령어역할
huma scanopenapi.yaml을 자동 감지하고 엔드포인트를 스캔한다
huma scan --from <file>OpenAPI, JSON 배열, YAML 등 지정한 파일에서 스캔한다
huma next다음 미완료 엔드포인트를 보여주거나, 현재 테스트를 검증하고 전진한다
huma verify현재 엔드포인트의 Hurl 테스트를 실행하고, 통과하면 전진한다
huma status진행 상황을 보여준다 (TODO/PASS/IMPROVE/DONE 카운트)
huma prompt현재 TODO에 대한 에이전트 프롬프트를 출력한다 (부수 효과 없음)

설정 파일 없음. DSL 없음. “10분이면 첫 번째 테스트가 나온다"가 설계 목표다.


래칫 루프

전체 워크플로우는 세 단계다.

openapi.yaml --> huma scan --> session
                                  |
                            huma next <--+
                              |          |
                              v          |
                            TODO         |
                          (no .hurl)     |
                              |          |
                        agent writes     |
                         .hurl file      |
                              |          |
                              v          |
                         PASS/IMPROVE ---+

1. 엔드포인트 스캔

프로젝트 루트에 openapi.yaml이 있으면 인자 없이 실행하면 된다.

huma scan
# Auto-detected openapi.yaml
# Scanned 42 endpoints

OpenAPI가 없는 레거시 프로젝트라면? --from으로 직접 지정한다. OpenAPI, JSON 배열, endpoints.yaml 모두 지원한다.

huma scan --from endpoints.yaml
# Scanned 42 endpoints

42개의 엔드포인트가 전부 TODO 상태로 세션에 등록된다.

2. 다음 할 일 확인

huma next
# TODO  GET /api/v1/users
# Source: internal/api/user/handler.go:25
# Handler: ListUsers
#
# ## Handler source
# func (h *Handler) ListUsers(c *gin.Context) { ... }
#
# ## Instructions
# 1. Write hurl/get_api_v1_users.hurl
# 2. Run `huma next`

에이전트가 필요로 하는 모든 것이 한 화면에 나온다. 핸들러 소스 코드, Hurl 파일 경로, 작성 지침. 에이전트가 grep할 필요가 없다. huma next가 프롬프트까지 만들어준다.

3. 테스트 작성

에이전트가 Hurl 파일을 작성한다. golden path(정상 케이스) + 최소 하나의 에러 케이스(400/401/404).

4. 검증과 전진

huma next
# PASS  GET /api/v1/users → hurl/get_api_v1_users.hurl
# TODO  POST /api/v1/auth/login

통과하면 PASS로 잠기고, 다음 TODO가 나온다. 실패하면 피드백과 함께 같은 엔드포인트에 머문다. 에이전트는 “다 했습니다"를 선언할 수 없다. huma next가 TODO를 찾는 한 루프는 계속된다.

huma status
# 15/42 PASS  |  0 IMPROVE  |  27 TODO

래칫 상태

각 엔드포인트는 네 가지 상태를 거친다.

TODO → PASS → (완료)
TODO → IMPROVE → PASS (또는 DONE)
상태의미
TODO.hurl 파일이 없다. 에이전트에게 핸들러 소스 + 예상 응답 + Hurl 예제가 제공된다
IMPROVEHurl은 존재하지만 응답 상태 코드가 누락되어 있다. 구체적으로 어떤 코드가 빠졌는지 표시된다
PASS예상되는 모든 응답 상태 코드가 커버되었다
DONE재시도 후에도 커버리지가 정체. 현재 수준에서 수용한다

IMPROVE가 의미하는 것은 명확하다. OpenAPI나 소스 분석에서 추출한 예상 응답 상태 코드(200, 400, 401, 404 등) 중 Hurl 테스트에서 검증하지 않는 코드가 있다는 뜻이다. 에이전트는 어떤 상태 코드가 빠졌는지 정확히 알 수 있다.

방향은 하나뿐이다. TODO에서 시작해서 PASS나 DONE에서 끝난다. 역방향 전이는 없다. 이것이 래칫이다.


두 가지 모드

huma는 서버 없이도, 서버를 띄워도 동작한다. 프로젝트의 상황에 맞는 모드를 선택하면 된다.

Static 모드 (서버 없음)

manifest.yamltesting.server 블록이 없으면 Static 모드로 동작한다. 서버를 띄우지 않는다.

apiVersion: yongol/v1
kind: Project
metadata:
  name: my-project
backend:
  lang: go
  framework: gin
  module: github.com/org/project
testing:
  base_url: "http://localhost:8080"
  hurl_dir: "hurl"
  hurl_variables:
    host: "http://localhost:8080"

이 모드에서 huma는 OpenAPI 또는 소스 분석에서 예상 응답 상태 코드를 추출하고, Hurl 파일이 해당 상태 코드를 커버하는지 검사한다. 서버를 띄울 수 없는 레거시 프로젝트에서 테스트 스캐폴드를 먼저 잡을 때 유용하다.

Live 모드 (서버 실행)

testing.server 블록을 추가하면 Live 모드가 활성화된다.

testing:
  # ... 위와 동일, 추가로:
  server:
    build: "go build -o ./server.test ./cmd/server"
    start: "./server.test"
    ready: "/api/health"

huma가 바이너리를 빌드하고, 서버를 시작하고, 헬스체크를 기다리고, Hurl을 실행한다. 헬스체크 실패 시 에이전트에게 서버를 먼저 시작하라고 안내한다. 런타임 검증까지 포함한 완전한 래칫이다.


언어를 가리지 않는다

huma는 Go, Python, Node.js 세 언어를 지원한다.

언어어댑터분석기backend.lang
GoGoAdaptergo/astgo (기본)
PythonPythonAdapterregexpython
Node.jsNodeAdapterregexnode

어댑터가 각 언어의 빌드, 서버 시작, 커버리지 수집을 추상화한다. Hurl 테스트 자체는 HTTP 레벨이므로 언어와 무관하다. 같은 래칫 루프가 Django 백엔드에도, Express 백엔드에도 적용된다.

이것은 의도적인 설계다. API 테스트는 구현 언어가 아니라 계약을 검증한다. Hurl이 plain text HTTP 요청이기 때문에 가능한 일이다.


에이전트 네이티브

huma는 사람을 위한 도구가 아니다. AI 에이전트를 위한 도구다.

huma next의 출력을 보면 알 수 있다. 핸들러 소스 코드, 예상 파일 경로, 작성 지침 — 에이전트가 다음 행동을 결정하는 데 필요한 정보가 전부 한 번에 나온다. Ryan et al.은 LLM에게 실행 경로를 분해하여 프롬프트를 제공하면 테스트 커버리지가 2배 향상된다고 실증했다 (Ryan et al., FSE 2024). huma next가 하는 일이 정확히 이것이다 — 에이전트가 “이 핸들러 소스를 읽어야 하는데 어디 있지?“라고 추가 탐색을 할 필요가 없다.

huma prompt는 더 노골적이다. 현재 TODO 엔드포인트에 대한 에이전트 프롬프트를 출력한다. 부수 효과 없음. 에이전트에게 복사-붙여넣기 없는 루프를 제공한다.

에이전트에게 필요한 지시는 한 문장이다:

huma next를 실행하고, TODO가 0이 될 때까지 반복해.


에러는 규칙 ID를 가진다

huma의 모든 에러 메시지에는 규칙 ID가 붙는다.

[H-01] Hurl file not found at expected path
  ▶ Check `huma next` output for expected filename

[A-02] Server build command failed
  ▶ go build -cover: exit status 1
접두사도메인
M-manifest.yaml 검증
E-엔드포인트 입력 검증
H-Hurl 파일 검증
S-세션 상태 검증
A-어댑터/서버 검증

에이전트에게 “에러를 고쳐"라고 말하는 것과 “[H-01] 에러를 고쳐"라고 말하는 것의 차이. 규칙 ID가 있으면 에이전트가 에러를 분류하고, rulebook에서 원인과 해결책을 찾고, 정확한 수정을 한다. 자연어 에러 메시지만으로는 LLM이 원인을 추측해야 한다.

이것이 Reins Engineering의 원칙이다. 피드백은 기계적이고, 구조적이고, 반복 가능해야 한다.


juicer → huma → yongol 파이프라인

레거시 코드베이스가 있다. API 스펙도 없고, 테스트도 없고, SSOT도 없다. 어디서부터 시작하는가?

세 도구가 체이닝된다.

레거시 코드베이스
    │
    ▼
juicer ──► openapi.yaml    (API 스펙 추출)
    │
    ▼
huma ──► hurl/*.hurl        (테스트 생성)
    │
    ▼
yongol ──► 리팩토링된 코드  (SSOT 기반 재구축)

juicer가 레거시 코드에서 OpenAPI 스펙을 뽑아낸다. huma가 그 스펙을 받아 모든 엔드포인트의 Hurl 테스트를 생성한다. yongol이 테스트가 검증된 코드를 SSOT 기반으로 재구축한다.

핵심은 manifest.yaml이 huma와 yongol 사이에 공유된다는 것이다. huma에서 래칫을 돌리며 쓴 manifest가 yongol로 넘어갈 때 전환 비용이 제로다. 같은 설정 파일, 같은 프로젝트 구조.

yongol의 SSOT 중 하나가 Hurl이다. specs/tests/에 Hurl 파일을 작성하면 yongol validate가 OpenAPI, 상태 기계, manifest.auth와 교차 검증한다. 그러나 Hurl 파일 자체를 처음부터 작성하는 것은 yongol의 범위가 아니다. huma가 그 빈자리를 채운다.

yongol이 뼈대(용골)라면, huma는 선체의 수밀성을 한 구획씩 테스트하는 검사관이다. 한 구획이라도 빠지면 배는 침몰한다. huma는 한 구획도 빠뜨리지 않는다.

yongol 없이도 huma는 독립적으로 동작한다. 어떤 SaaS 백엔드든 openapi.yaml만 있으면 래칫이 돌아간다. Go든 Python이든 Node.js든.


10분이면 충분하다

go install github.com/park-jun-woo/huma@latest

또는 Claude Code 스킬로 설치한다:

npx skills add park-jun-woo/huma

스킬로 설치하면 AI 에이전트가 워크플로우를 자동으로 학습한다.

  1. openapi.yaml이 있으면 huma scan (없으면 huma scan --from endpoints.yaml)
  2. huma next — 프롬프트를 읽고 Hurl을 작성한다
  3. huma next — 검증하고 다음으로 넘어간다
  4. TODO가 0이 될 때까지 반복한다

설정 파일 없음. 학습 곡선 없음. 42개 엔드포인트가 있으면 42개 전부 테스트가 생긴다.

에이전트에게 “다 했습니다"라고 선언할 권한을 주지 마라. 기계가 판정하게 하라. 그것이 래칫이다.

코드: github.com/park-jun-woo/huma


출처

  • Cemri, M., Pan, M. Z., Yang, S., Agrawal, A., Chopra, K., Tiwari, M., Keutzer, K., Parameswaran, A., & Stoica, I. (2025). Why Do Multi-Agent LLM Systems Fail? NeurIPS 2025, Datasets and Benchmarks Track. arxiv.org/abs/2503.13657
  • Kim, M., Xin, Q., Sinha, S., & Orso, A. (2022). Automated Test Generation for REST APIs: No Time to Rest Yet. ISSTA 2022, 289–301. dl.acm.org/doi/10.1145/3533767.3534401
  • Ryan, G., Jain, S., Shang, M., Wang, S., Ma, X., Ramanathan, M. K., & Ray, B. (2024). Code-Aware Prompting: A Study of Coverage-Guided Test Generation in Regression Setting using LLM. FSE 2024, Article 59. dl.acm.org/doi/10.1145/3643769
  • Jimenez, C. E., Yang, J., Wettig, A., Yao, S., Pei, K., Press, O., & Narasimhan, K. (2024). SWE-bench: Can Language Models Resolve Real-World GitHub Issues? ICLR 2024. arxiv.org/abs/2310.06770
  • Xu, F., et al. (2024). TheAgentCompany: Benchmarking LLM Agents on Consequential Real World Tasks. arxiv.org/abs/2412.14161
  • Lu, Q., Ding, L., Cao, S., Liu, X., Zhang, K., Zhang, J., & Tao, D. (2025). Runaway is Ashamed, But Helpful: On the Early-Exit Behavior of LLM-based Agents in Embodied Environments. arxiv.org/abs/2505.17616
  • Golmohammadi, A., Zhang, M., & Arcuri, A. (2024). Testing RESTful APIs: A Survey. TOSEM, 33(1), 27:1–27:41. dl.acm.org/doi/10.1145/3617175
  • Martin-Lopez, A., Segura, S., & Ruiz-Cortes, A. (2019). Test Coverage Criteria for RESTful Web APIs. A-TEST ‘19, 15–22. dl.acm.org/doi/10.1145/3340433.3342822
  • Atlidakis, V., Godefroid, P., & Polishchuk, M. (2019). RESTler: Stateful REST API Fuzzing. ICSE 2019, 748–758. dl.acm.org/doi/10.1109/ICSE.2019.00083
  • Arcuri, A. (2019). RESTful API Automated Test Case Generation with EvoMaster. TOSEM, 28(1), 3:1–3:37. dl.acm.org/doi/10.1145/3293455
  • Karlsson, S., Causevic, A., & Sundmark, D. (2020). QuickREST: Property-based Test Generation of OpenAPI-Described RESTful APIs. ICST 2020, 131–141. arxiv.org/abs/1912.09686
  • Corradini, D., Zampieri, A., Pasqua, M., & Ceccato, M. (2021). Restats: A Test Coverage Tool for RESTful APIs. ICSME 2021, 594–598. arxiv.org/abs/2108.08209
  • Scholten, T., Orru, M., Verwer, S., & Pol, J. (2025). WuppieFuzz: Coverage-Guided, Stateful REST API Fuzzing. arxiv.org/abs/2512.15554
  • Atlidakis, V., Godefroid, P., & Polishchuk, M. (2021). REST API Fuzzing by Coverage Level Guided Blackbox Testing. arxiv.org/abs/2112.15485

관련 글