메뉴
HN
Hacker News • 58일 전

병렬 Claude Code 에이전트용 로컬 병합 큐

IMP
7/10
핵심 요약

여러 Claude Code 에이전트가 동시에 작업할 때 발생하는 코드 병합 충돌과 중복 빌드 문제를 해결하는 무료 로컬 병합 큐(merge queue) 도구를 소개합니다. GitHub Actions 등의 클라우드 비용 없이 개발자의 로컬 머신에서 직관적으로 에이전트들의 작업을 직렬화하여 안전하게 통합할 수 있게 해줍니다. 다수의 AI 코딩 에이전트를 동시에 운용하는 실무 개발자들에게 필수적인 충돌 방지 및 자동화 솔루션입니다.

번역된 본문

Claude Code Merge Queue 🚦: 병렬로 실행되는 Claude Code 에이전트를 위한 로컬 무료 병합 큐입니다. 여러 에이전트가 동시에 코드를 반영(land), 빌드, 테스트할 때 이를 직렬화하여 푸시 경쟁(push race), 중복된 무거운 빌드, 공유 리소스 테스트의 불안정성(flakiness) 문제가 발생하지 않도록 막아줍니다.

⚡ 빠른 시작 npm install --save-dev claude-code-merge-queue

또는: pnpm add -D / yarn add -D / bun add -d

npx claude-code-merge-queue init

목차 ⚙️ 설정(Configuration) 🆚 GitHub 병합 큐와의 비교 🧰 제공 기능 🚨 비상 탈출구(Emergency hatch) 🔍 제한 사항 📄 라이선스

⚙️ 설정 (Configuration) 모든 설정은 단 하나의 파일에 저장됩니다 — 모든 필드와 주석은 examples/claude-code-merge-queue.config.mjs에서 확인할 수 있습니다. 핵심 요약은 다음과 같습니다:

export default { branchPrefix: "lane/", // lane/1, lane/2, ... worktreeSuffix: "-lane-", // ../your-repo-lane-1 portBase: 3000, // n번째 lane은 portBase + n 포트를 사용 integrationBranch: "main", // 에이전트가 코드를 반영하는 브랜치 — 아래 참조 productionBranch: null, // 2단계 모델을 위한 설정 — 아래 참조 protectedBranches: [], // 위 두 브랜치 외에 추가로 보호할 브랜치; 대부분의 저장소에서는 필요 없음 regenerableFiles: [], // 빌드 도구가 다시 작성하는 파일 — rebase 시 이 파일들이 막지 않음 symlinks: [".env", ".env.local", "node_modules"], buildOutputDirs: ["dist", "build", ".next"], // 미리보기 시 체크아웃에 복사하지 않음 checkCommand: "npm run check", // 실제 코드 반영을 통제하는 명령어 — 아래 참조 checksRequired: true, // false = 검사 없이 실행; 아래 참조 };

설정이 잘못된 경우(빈 브랜치 이름, 음수 포트, productionBranch가 integrationBranch와 동일 등) 명령어가 로드되는 즉시 모든 문제를 나열하며 명확하게 에러를 발생시킵니다. 3단계를 거친 후 알 수 없는 미스터리한 실패를 겪지 않아도 됩니다.

🆚 GitHub 병합 큐와의 비교

  • GitHub 병합 큐: 프라이빗 저장소는 Enterprise Cloud 전용 / 반영 시마다 GitHub Actions 시간(비용) 발생 / Pull Request 필요.
  • Claude Code 병합 큐: 모든 요금제, 모든 저장소에서 사용 가능 / 자신의 머신에서 실행되어 비용 $0 / Pull Request 없이 직접 rebase + push 지원.

아이디어는 동일합니다. 랜딩을 직렬화하고, 병합 전에 테스트하며, 히스토리를 깔끔하게 유지하는 것입니다. 다만 누군가의 과금되는 클라우드 대신 로컬에서 실행된다는 점이 다릅니다.

🧰 제공 기능 (명령어)

  • claude-code-merge-queue hook worktree-create: Claude Code WorktreeCreate 훅입니다. Claude Code Merge Queue의 번호가 매겨진 lane을 Claude의 기본 worktree 생성에 연결합니다.
  • claude-code-merge-queue build-lock -- : 머신 전체에 걸쳐 직렬화된 방식으로 빌드 명령어()를 실행합니다.
  • claude-code-merge-queue land: FIFO 큐를 통해 통합 브랜치에 lane을 rebase하고 push합니다. 두 lane이 동시에 push 하는 일이 발생하지 않습니다. 에이전트가 스스로 실행합니다.
  • claude-code-merge-queue sync: 메인 체크아웃을 fast-forward하여 개발 서버가 방금 반영된 코드를 볼 수 있게 합니다. lockfile이 변경된 경우 의존성을 다시 설치합니다.
  • claude-code-merge-queue promote: 통합 브랜치를 프로덕션에 배포합니다. 사람 전용이며 에이전트의 지시 사항에 포함되거나 자동화되지 않습니다.
  • claude-code-merge-queue preview: 빌드 없이 확인할 수 있도록 커밋되지 않은 변경 사항을 포함하여 lane의 라이브 작업 트리를 메인 체크아웃에 즉시 미러링합니다.
  • claude-code-merge-queue port: 디렉터리 이름에서 파생된 lane의 개발 서버 포트를 출력합니다.
  • claude-code-merge-queue prune: 이미 반영된 형제 lane worktree를 요청 시 제거합니다.

pre-push 훅은 land 명령어를 필수로 만듭니다. 통합 브랜치에 대한 직접적인 git push는 거부되며, 대신 실행해야 할 실제 명령어를 안내합니다. 또한 같은 훅이 통과를 허용하기 전에 checkCommand를 실행합니다. checkCommand가 구성되어 있지 않으면 기본적으로 모든 push가 실패합니다. 모든 차단에는 해결책(🚨 비상 탈출구 참조)이 있지만, 범용 플래그가 아닌 특정 브랜치 이름을 지정해야 합니다.

📝 init 명령어가 작성하는 내용

  • claude-code-merge-queue.config.mjs — integrationBranch 및 checkCommand가 자동 감지됩니다.
  • CLAUDE.md (또는 기존 파일에 추가) — Claude Code에게 요청받지 않아도 테스트 통과 시 자신의 작업을 반영하도록 지시합니다.
  • .claude/settings.json — 기존 설정을 건드리지 않고 WorktreeCreate 훅이 연결됩니다.
  • .husky/pre-push — 생성되거나 기존 파일에 추가됩니다.
원문 보기
원문 보기 (영어)
Claude Code Merge Queue 🚦 The local, zero-cost merge queue for parallel Claude Code agents. Several agents land, build, and test at the same time — this serializes it so push races, redundant heavy builds, and shared-resource test flakiness can't happen. ⚡ Quickstart npm install --save-dev claude-code-merge-queue # or: pnpm add -D / yarn add -D / bun add -d npx claude-code-merge-queue init Contents ⚙️ Configuration 🆚 vs. GitHub's Merge Queue 🧰 What's in the box 🚨 The emergency hatch 🔍 Know the limits 📄 License ⚙️ Configuration Everything lives in one file — see examples/claude-code-merge-queue.config.mjs for every field with comments. The short version: export default { branchPrefix : "lane/" , // lane/1, lane/2, ... worktreeSuffix : "-lane-" , // ../your-repo-lane-1 portBase : 3000 , // lane n gets portBase + n integrationBranch : "main" , // where agents land — see below productionBranch : null , // set this for a two-stage model — see below protectedBranches : [ ] , // extra branches beyond the two above; most repos need none regenerableFiles : [ ] , // files a build tool rewrites — never block a rebase on these symlinks : [ ".env" , ".env.local" , "node_modules" ] , buildOutputDirs : [ "dist" , "build" , ".next" ] , // preview never copies these onto your checkout checkCommand : "npm run check" , // what actually gates a landing — see below checksRequired : true , // false = deliberately run with none; see below } ; A malformed config (empty branch names, a negative port, productionBranch equal to integrationBranch , ...) fails loud with every problem listed, the moment any command loads it — not a mysterious failure three steps later. 🆚 vs. GitHub's Merge Queue GitHub Merge Queue Claude Code Merge Queue Private repo Enterprise Cloud only Any plan, any repo Cost per landing GitHub Actions minutes, every queue attempt $0 — runs on your own machine Requires A pull request Nothing — direct rebase + push Same idea — serialize landings, test before merge, keep history clean — run locally instead of in someone else's billed cloud. 🧰 What's in the box Command What it does claude-code-merge-queue hook worktree-create A Claude Code WorktreeCreate hook. Plugs Claude Code Merge Queue's numbered lanes into Claude's native worktree creation. claude-code-merge-queue build-lock -- <cmd> Runs <cmd> — your build — serialized across every lane, machine-wide. claude-code-merge-queue land Rebases and pushes your lane onto the integration branch through a FIFO queue, so two lanes are never mid-push at once. Agents run this themselves. claude-code-merge-queue sync Fast-forwards your main checkout so a dev server actually sees what just landed — and re-installs dependencies if the lockfile changed. claude-code-merge-queue promote Ships the integration branch to production. Human-only — never in an agent's instructions, never automated. claude-code-merge-queue preview Instantly mirrors a lane's live working tree — uncommitted changes included — onto the main checkout, so you can look at it without a build. claude-code-merge-queue port Prints a lane's dev-server port, derived from its own directory name. claude-code-merge-queue prune Removes already-landed sibling lane worktrees on demand. A pre-push hook makes land non-optional: a direct git push straight to the integration branch is rejected, with the actual command to run instead, and the same hook runs checkCommand before allowing a landing through — no checkCommand configured means every push fails by default. There's a way out for every block (see 🚨 The emergency hatch), but it takes naming the specific branch, not a generic flag. 📝 What init writes claude-code-merge-queue.config.mjs — integrationBranch and checkCommand auto-detected. CLAUDE.md (or appends to yours) — tells Claude Code to land its own work once green, without being asked. .claude/settings.json — the WorktreeCreate hook wired in, without touching anything else already there. .husky/pre-push — created or appended to, if you already have Husky. If you don't, init tells you rather than silently writing to the untracked .git/hooks/pre-push . package.json scripts — land , sync , promote , preview , preview:restore , skipping any you've already defined yourself. claude-code-merge-queue-preflight.mjs — a self-contained safety net that runs before land / sync , so a stale branch fails with a real diagnosis instead of a bare command not found . 🚨 The emergency hatch Every blocked push — the integration branch, productionBranch , anything in protectedBranches — has a real way through it. One env var, no prompts, no second factor to remember: CLAUDE_CODE_MERGE_QUEUE_EMERGENCY_PUSH=1 git push origin HEAD:main This is a convention, not a hard guarantee: it stops mistakes and stray pushes, not an adversarial agent that sets the var itself. 🔍 Know the limits No human reviews any of this before it lands. checkCommand passing is the only gate — a real test suite and echo ok look identical to this tool. Want a human on every change? This is missing that step on purpose. Locks are crash-safe by PID liveness, not a timeout. kill -9 anything mid-claim and the next process notices the PID is dead and reclaims it — no stale locks, no timeout to tune. One machine, not a fleet. The FIFO queue lives in local temp storage — two machines landing at once just get git's ordinary non-fast-forward rejection. Not a security boundary. Every guardrail here stops mistakes and convention drift, not an adversarial agent — shell access always means git push --no-verify or editing the config on purpose. A slow checkCommand is a real throughput ceiling. The FIFO lock holds for its entire duration — a 3–4 minute suite caps you well under 20 landings/hour. Rebase conflicts abort, they never guess. git rebase --abort on any conflict, working tree left clean — CLAUDE.md tells the agent to resolve it and re-run land . 📄 License MIT. Fork it, rename it, argue with the config shape — that's the point.
관련 소식