노트북 덮고 자는 동안 Claude Code·Codex·Copilot·Pi 같은 코딩 에이전트를 한 번에 한 step씩 커밋·롤백·재시도하며 굴려놓고, 아침에 깨끗한 git 브랜치 + 실행 로그로 받는 TypeScript CLI. 1.8k stars / MIT / Node 20+ / 2026-03-31 생성, 2개월 만에 trending #25 진입.
정확히 무엇을 하는 도구인가
gnhf는 — 이름 그대로 Good Night, Have Fun — 사용자가 자거나 자리를 비운 사이에 코딩 에이전트를 한 번에 한 step씩 무한 루프로 돌리는 오케스트레이터다. 각 iteration은 "작은 변화 → git commit → 다음 iteration"이라는 원자적 사이클을 갖고, 실패하면 git reset --hard로 롤백한다. 아침에 일어나면 brand-new gnhf/<slug> 브랜치에 깨끗한 commit 더미와 무엇이 일어났는지 적은 로그가 기다리고 있다.
제빵사가 자는 사이에 반죽기가 한 번 돌면 빵 한 덩이가 나오고, 잘 구워졌으면 트레이에 올리고(commit), 타거나 모양이 망가졌으면 버린다(reset). 다음 반죽은 이전 트레이에 뭐가 있는지 보고 다시 시작한다.
아침에 일어나면 트레이 위에 빵 10개가 있고, 각각 어떤 레시피로 어떻게 구워졌는지가 적혀 있는 식이다. 빵공장 = gnhf, 반죽기 = Claude/Codex CLI, 트레이 = git 브랜치, 레시피 노트 = notes.md.
2026년 봄, AI 코딩 에이전트 생태계에서 차지한 자리
2026년 들어 Claude Code·Codex·Copilot CLI 같은 비대화식(non-interactive) 코딩 에이전트가 흔해지면서, "밤새 알아서 굴려놓고 아침에 결과만 본다"는 패턴이 본격적으로 떠올랐다. 이를 가능하게 한 두 가지 선행 작업이 있다:
gnhf는 이 두 흐름을 가져와서 production-grade UX로 다듬은 결과물이다.
| 관점 | ralph / 단순 while loop | gnhf |
|---|---|---|
| 커밋 단위 | 전체 task 끝나야 1 commit | iteration마다 atomic commit → cherry-pick·revert 자유 |
| 실패 처리 | 실패 시 그냥 멈춤 | 3종 분류: 일시적 → 백오프, 영구 → abort, commit 실패 → 다음 step에 "복구해줘" 위임 |
| 병렬 실행 | 지원 X | --worktree로 동일 repo에서 여러 에이전트 동시 실행 |
| 에이전트 락인 | 특정 CLI 종속 | 7개 native + ACP 프로토콜 → 에이전트 무관 |
| 중단/재개 | 처음부터 다시 | gnhf/<branch> 위에서 다시 실행 → history 이어받기 |
| 슬립 방지 | OS에 맡김 | macOS caffeinate / Linux systemd-inhibit / Win PowerShell 내장 |
2026년 5월 X(트위터)에서 "밤새 에이전트 돌려놓고 아침에 PR 리뷰" 워크플로가 핫토픽이 되었고, gnhf는 그 워크플로에 가장 적합한 도구 중 하나로 빠르게 입소문을 탔다. 특히 "complete no-op iteration도 실패로 간주" 같은 디테일 — 즉 에이전트가 사실상 아무것도 안 하고 "끝났다"고 거짓말하는 경우까지 잡아내는 — 이 신뢰성을 만들어낸다.
단순한 TypeScript CLI지만, 굉장히 신중하게 골라진 도구들
| 레이어 | 도구 | 역할 / 선택 이유 |
|---|---|---|
| 언어 | TypeScript 5.8+ | type-safe + Node 20+ ESM 네이티브 |
| 런타임 | Node.js ≥20 | ESM·Fetch·AbortController 등 표준 API 안정화 버전 |
| 패키지 매니저 | pnpm 11 | monorepo·workspaces·deterministic install |
| 빌드 | tsdown 0.21 | esbuild 기반 초고속 ts→mjs 번들러 (단일 dist/cli.mjs 산출) |
| CLI 파서 | commander 14 | 오랜 검증을 거친 사실상 표준 |
| 설정 파서 | js-yaml 4 | ~/.gnhf/config.yml 읽고 쓰기 |
| 도구 | 역할 |
|---|---|
| vitest 4.1 | 유닛 테스트 + e2e 테스트 + v8 커버리지 |
| acp-mock / acpx 0.6 | ACP 프로토콜 mocking으로 외부 에이전트 없이 테스트 |
| ESLint 9 + typescript-eslint 8 + prettier 3 | 코드 스타일 + 정적 분석 |
| release-please | Conventional Commits → 자동 changelog + npm publish |
gnhf는 에이전트 자체를 번들하지 않는다 — 사용자가 별도로 설치한 CLI를 spawn해서 호출하는 구조. 따라서 의존성은 매우 가볍다(commander와 js-yaml 단 2개).
| 에이전트 | 플래그 | 호출 방식 |
|---|---|---|
| Claude Code | --agent claude | claude 비대화식 모드 직접 spawn |
| OpenAI Codex | --agent codex | codex exec 비대화식 |
| GitHub Copilot CLI | --agent copilot | 비대화식 JSONL 모드 |
| Pi CLI | --agent pi | JSON 모드 + --no-session |
| Rovo Dev | --agent rovodev | 로컬에서 acli rovodev serve 자동 기동 |
| OpenCode | --agent opencode | 로컬 opencode serve 자동 기동 + 세션 생성 |
| ACP target | --agent acp:<name> | 번들된 acpx를 통해 어떤 ACP 호환 에이전트도 가능 |
acpx(openclaw가 만든 ACP 멀티플렉서)를 내장해 acp:gemini 같은 짧은 이름으로 부른다.한 iteration이 어떻게 흘러가는가
전통적 LLM 스크립트는 task가 끝나야 결과를 받는다. gnhf는 각 iteration 자체가 하나의 git commit이다. 그 결과:
git log gnhf/foo를 보면 그 밤에 무슨 결정을 했는지 시간순으로 보임git revert 또는 git rebase -i로 빼낼 수 있음gnhf 1: refactor X 또는 (옵션) refactor(api): X Conventional Commits 형식모든 에러를 같이 처리하면 안 된다. gnhf는 신중하게 나눈다:
| 유형 | 예시 | 대응 |
|---|---|---|
| 일시적 (retryable) | 네트워크 끊김, rate-limit | 지수 백오프로 재시도 |
| 영구 (permanent) | Claude 크레딧 잔액 0, 인증 만료 | 즉시 abort + 로그 경로 출력 |
| commit 실패 | pre-commit hook 실패 | 다음 iteration에 "복구해줘" 위임 + 작업 트리 보존 |
| no-op | 에이전트가 변경 0건 + "성공" 보고 | 실패로 카운트 (3연속이면 abort) |
이 디테일이 "사실은 못하는 일을 끝났다고 보고하는" LLM 특유의 거짓말을 막아준다.
각 iteration은 새로운 LLM 호출이라 컨텍스트가 리셋된다. gnhf는 .gnhf/runs/<runId>/notes.md에 매 iteration의 요약을 append하고, 다음 prompt 조립 시 이 파일을 주입한다. 결과적으로 에이전트는 "방금 직전에 내가 무엇을 시도했고 무엇이 실패했는가"를 기억한 채 다음 step에 진입한다.
건망증이 심한 청소부 10명이 1시간씩 교대로 같은 집을 청소하는데, 각자 들어올 때 전임자의 메모를 읽고 들어가는 것과 같다. "거실은 끝, 부엌 싱크대 막힌 거 빼고는 다 했음" 같은 메모가 있으면 다음 사람은 부엌 싱크대만 집중하면 된다.
~5MB짜리 작은 레포지만 모든 책임이 명확하게 분리됨
src/core/orchestrator.ts이 파일이 사실상 gnhf의 심장이다. git ↔ 에이전트 ↔ notes.md ↔ TUI ↔ 종료 조건을 모두 조율한다. 단일 함수 안에 다 박지 않고 의존성 주입으로 git/agent/clock을 받아 mock-orchestrator.ts에서 테스트할 수 있게 분리한 것이 깔끔하다.
skills/gnhf/SKILL.mdgnhf는 자기 자신을 Anthropic의 Agent Skill로도 배포한다. 즉 Claude Code 같은 host 에이전트가 "내가 자고 일어나야 하는데 어떻게 gnhf를 쓰지?"를 학습할 수 있게 메타 가이드를 제공한다. Hands-Off 모드(완전 위임)와 Companion 모드(중간 점검) 두 가지 사용 패턴을 정의한다.
.gnhf/runs/<runId>/실행 산출물 — prompt.md(원본 prompt), notes.md(누적 메모), gnhf.log(JSONL lifecycle 로그), iteration-<n>.jsonl(에이전트 스트리밍 출력). 모두 .gitignore 처리되어 깨끗한 branch만 남는다.
이 레포를 깊게 읽으면 배울 수 있는 것들
.mjs 번들 만들어 bin 등록renderer-diff.ts)git worktree로 동일 repo에 병렬 환경 만들기 (LLM 여러 마리 동시 굴리기)2^n × jitter 패턴)sleep.ts)acpx) 활용"내가 만든 LLM CLI"를 gnhf의 7번째 에이전트로 추가해보자. src/core/orchestrator.ts에서 에이전트 spawn하는 부분을 찾아 똑같이 추가하고, "성공 시 JSON 반환" 약속만 지키면 끝. 이 과정에서 모든 에이전트가 따르는 공통 인터페이스가 무엇인지 자연스럽게 학습된다.
바닥이 낮아 누구나 시도 가능
| 항목 | 요구사항 |
|---|---|
| OS | macOS / Linux / Windows 모두 지원 |
| Node.js | ≥20 (ESM·Fetch·AbortController 안정 버전) |
| git | ≥2.20 정도 (worktree 정상 동작 버전) |
| 패키지 매니저 | npm 또는 (소스 빌드 시) pnpm 11 + corepack |
| 에이전트 CLI | 최소 1개: claude / codex / copilot / pi / rovodev / opencode 중 하나, 사전 로그인 필요 |
| 비용 | gnhf 자체는 무료, 에이전트 호출 비용은 사용자 부담 (밤새 돌리면 토큰 비용 폭증 가능) |
| 네트워크 | 에이전트 API 호출용. GNHF_TELEMETRY=0으로 텔레메트리 차단 가능 |
아무 가드 없이 밤새 Claude Sonnet 돌리면 아침에 십수만~수십만 원 청구가 가능하다. 반드시 --max-iterations·--max-tokens·--stop-when 중 하나는 걸어둘 것. gnhf는 --max-tokens 도달 시 iteration 중간에도 abort한다.
난이도별 4개
아무 git repo에 들어가서 깨끗한 작업 트리 상태에서 다음을 실행:
3 iteration이 끝나면 git log gnhf/<slug>로 어떤 commit이 생겼는지 본다. 목표: gnhf가 iteration마다 commit을 어떻게 쪼개는지 체감.
--stop-when으로 자연어 종료 조건유닛 테스트가 있는 작은 프로젝트에서:
목표: gnhf가 매 iteration 에이전트의 출력을 보고 "조건 만족" 여부를 어떻게 판정하는지 notes.md로 확인.
--worktree로 병렬 3 에이전트같은 repo에 3 작업을 동시에 굴린다:
목표: <repo>-gnhf-worktrees/ 디렉토리에 각자 격리된 작업 환경이 생기는 걸 확인하고, 어떤 worktree를 merge할지 선택하는 경험.
src/core/orchestrator.ts에서 --agent 분기 처리 부분을 찾아, 자체 ACP 호환 에이전트(또는 자체 CLI wrapper)를 추가한다. 테스트는 e2e/ 디렉토리의 mock 패턴을 따라 작성.
목표: 실제 OSS에 컨트리뷰션할 수 있을 정도로 코드베이스 친숙해지기. + PR 보너스 가능.
gnhf 한 레포가 아니라, 그 주변 생태계를 4주에 걸쳐
| 주차 | 주제 | 구체 액션 |
|---|---|---|
| Week 1 | 야간 에이전트 패턴의 기원 | karpathy/autoresearch 레포 읽기 + ghuntley의 "ralph" 블로그 포스트 읽기. "왜 한 prompt를 무한 루프로 돌리면 잘 되는가?"의 직관 잡기. |
| Week 2 | Agent Skills 표준 | anthropics/skills 레포의 SKILL.md 표준 학습 후, gnhf의 skills/gnhf/SKILL.md를 다시 읽기. Hands-Off / Companion 모드 구분을 본인 도구에 적용해보기. |
| Week 3 | ACP & Multi-agent | openclaw/acpx 레포 읽기 + ACP 사양 (Agent Client Protocol) 훑기. gnhf가 어떻게 7종 에이전트를 추상화하는지 본인 코드에 옮기기. |
| Week 4 | OSS Release 자동화 | release-please + Conventional Commits로 자기 npm 패키지에 자동 changelog/release 설정해보기 — gnhf가 2개월에 42릴리스를 낼 수 있는 이유. |
처음 보는 용어 정리
git worktree add ../foo my-branch. gnhf는 이걸로 한 repo에 여러 에이전트를 격리해서 동시에 돌린다.--print, codex의 exec 같은 플래그가 활성화한다. 자동화에 필수.acpx가 reference 멀티플렉서.SetThreadExecutionState API를 PowerShell로 호출.feat:, fix:, chore: 같은 prefix로 commit 메시지의 의미를 약속하는 표준. release-please 같은 도구가 이걸 보고 자동 changelog를 만든다.skills/gnhf/SKILL.md를 통해 자기 자신 사용법을 가르친다.git status가 깨끗한 상태인지 확인gnhf --agent claude --max-iterations 2 "README의 첫 단락을 더 매력적으로 다시 써줘" 실행gnhf/<slug> 브랜치로 자동 이동된 상태. git log --oneline으로 commit 2개가 쌓였는지 확인.gnhf/runs/<runId>/notes.md 열어보기 — 에이전트가 iteration 사이에 무엇을 기억했는지 보이면 성공.