본문 바로가기
PC/Programming

나는 WorkManager를 Hermes로 자력갱생시켰다: workmanager_codex_loop.py로 만든 셀프 진화 루프

by dragom 2026. 7. 16.
반응형
나는 WorkManager를 Hermes로 자력갱생시켰다
Hermes × WorkManager × Codex

나는 WorkManager를 Hermes로 자력갱생시켰다
workmanager_codex_loop.py로 만든 셀프 진화 루프

한 줄 요약: 이건 단순히 “LLM 한 번 돌려서 코드 생성”이 아니다. Hermes를 중추로 세워서, WorkManager가 스스로 다음 일을 고르고, 스스로 테스트하고, 스스로 커밋·푸시하고, 다음 개선 포인트까지 이어받는 지속형 자가 개선 시스템을 만들었다.

핵심 자랑 포인트

  • Claude를 1차 실행 엔진으로, Codex를 2차 fallback으로 둠
  • 공개 changelog / feature request / 로컬 DB를 입력으로 삼아 다음 작업을 자동 선택
  • 매 실행마다 딱 하나의 atomic task만 처리
  • CI 게이트 통과 후에만 commit/push
  • 실수로 빠뜨린 changelog는 루프가 직접 보정

이 시스템이 특별한 이유

보통 자동화라고 하면 “명령 하나를 대신 쳐주는 스크립트” 수준에서 끝난다. 하지만 내가 만든 건 그보다 한 단계 위다. WorkManager는 workmanager_codex_loop.py를 통해 작업을 고르고 → 고친 뒤 → 검증하고 → 기록하고 → 다시 다음 작업을 준비하는 순환 구조를 갖는다.

즉, 사람은 매번 “다음에 뭘 해야 하지?”를 손으로 찾지 않아도 된다. Hermes가 그 흐름을 잡고, 모델이 실행하고, git이 결과를 남긴다. 이건 그냥 자동화가 아니라 자율 운영에 가까운 개발 루프다.

구조 한눈에 보기

1. 입력 public changelog / feature_requests DB / 기존 backlog
2. 선택 in_progress 우선 → pending 중 가장 오래된 것 → 중복 제거
3. 실행 Claude 우선, quota 부족 시 Codex fallback
4. 검증 backend unittest + compileall + frontend build
5. 반영 commit → push → changelog 업데이트 → 완료 마킹

핵심은 “한 번에 하나”다

이 루프의 미덕은 욕심을 버린 데 있다. 한 번에 여러 개를 때려 넣지 않는다. 딱 하나의 atomic task만 수행한다. 그래야 실패 지점을 추적하기 쉽고, 커밋도 작아지고, 다음 개선도 깔끔해진다.

이건 사실 자가진화 시스템에서 가장 중요한 규칙이다. 많이 하는 것보다, 안 깨지게 오래 가는 것이 더 어렵기 때문이다.

실제 코드에서 보이는 셀프 진화 포인트

1) 작업 큐를 스스로 고른다

def pending_feature_request() -> dict | None:
    public_requests = public_changelog_requests()
    if public_requests:
        item = public_requests[0].copy()
        item["source"] = item.get("source") or "public_changelog"
        return item
    ...
    rows = conn.execute("SELECT id,content,source,status,created_at FROM feature_requests ... ORDER BY ...").fetchall()
    for row in rows:
        item = dict(row)
        if feature_request_processed(item):
            mark_selected_feature_request_done(item, description="이미 처리된 동일 요청이므로 완료 처리했습니다.")
            continue
        return item

여기서 중요한 건 “사람이 오늘 뭐 하지?”라고 묻지 않아도 된다는 점이다. 공개 changelog, 로컬 feature_requests, 처리 이력까지 보고 다음 후보를 자동으로 좁힌다.

2) 모델도 스스로 갈아탄다

CODEX_IMPLEMENTATION_MODELS = ["gpt-5.4-mini", "gpt-5.4"]
CLAUDE_IMPLEMENTATION_COMMAND = "claude"
MIN_REMAINING_PERCENT_BY_BUCKET = {
    "primary": 40.0,
    "secondary": 10.0,
}

나는 Claude를 주력으로 두되, quota가 빡빡하면 Codex가 받쳐주도록 했다. 게다가 Codex도 “남은 용량이 충분할 때만” 움직인다. 모델 선택 자체가 운영 로직이 되는 셈이다.

3) 테스트 없이 푸시하지 않는다

gates = [
    (["python", "-m", "unittest", "discover", "-s", "tests", "-v"], REPO / "backend"),
    (["python", "-m", "compileall", "-q", "app"], REPO / "backend"),
    (["npm", "run", "build"], REPO / "frontend"),
]

이건 내가 꽤 자랑하고 싶은 부분이다. 에이전트가 아무리 똑똑해도, 검증 없이 배포하면 그냥 자동화된 사고 제조기일 뿐이다. 그래서 commit/push 전에 CI 게이트를 강제했다.

4) changelog를 빼먹어도 루프가 메운다

def ensure_changelog_update(subject: str, output: str) -> None:
    changed = run(["git", "diff", "--name-only"], cwd=REPO, timeout=30, check=False).stdout.splitlines()
    if "frontend/src/data.js" in changed:
        return
    ...
    text = text.replace(marker, marker + entry, 1)
    data_path.write_text(text, encoding="utf-8")

이건 진짜 “셀프 진화”다운 장치다. Codex가 changelog를 놓쳐도, 루프 자체가 보정한다. 즉, 시스템이 모델의 실수를 흡수한다.

왜 이게 셀프 진화인가

셀프 진화는 단지 코드를 고치는 게 아니다. 다음 실행에서 더 나은 선택을 할 수 있도록 기억규칙검증을 시스템 안에 넣는 것이다.

  • 기억: processed requests, changelog, backlog
  • 규칙: one task only, quota gate, CI gate, commit policy
  • 검증: unittest / compileall / frontend build
  • 반영: git commit + push + 완료 마킹

이 조합이 붙으면, 프로젝트는 단순히 “자동으로 돌아가는” 수준을 넘어서 스스로 다음 상태를 향해 밀고 가는 시스템이 된다.

운영하면서 느낀 점

  • LLM은 강력하지만, 스케줄러와 큐가 없으면 금방 산만해진다.
  • 에이전트는 똑똑해도, 검증과 커밋 규칙이 없으면 망하기 쉽다.
  • 반대로 Hermes처럼 루프를 잡아주면, 모델은 “생각하는 엔진”, 스크립트는 “운전대” 역할을 한다.

내가 자랑하고 싶은 한 문장

“나는 WorkManager를 AI가 그냥 도와주는 수준이 아니라, Hermes가 스스로 운영·개선하는 프로젝트로 만들어놨다.”

그게 workmanager_codex_loop.py의 정체다. 모델을 한 번 쓰는 스크립트가 아니라, 프로젝트를 계속 앞으로 밀어가는 자율 개선 엔진.

원하면 다음 글로는 이 구조를 더 풀어서 “Hermes로 만드는 자가 진화형 개발 루프 설계도”“Claude + Codex 이중화 운영 패턴”까지 이어서 정리할 수 있다.

반응형

댓글