Show HN: Python DSL을 사용한 태스크 러너, CI/CD 시스템으로 성장하는 Harmont
요약
Harmont는 Python DSL을 사용하여 CI/CD 파이프라인을 정의하고, 이를 로컬 Docker 환경과 Harmont Cloud의 관리형 러너 양쪽에서 동일하게 실행할 수 있게 하는 도구입니다. 이 접근 방식은 로컬 디버깅 결과와 실제 배포 결과를 바이트 단위로 일치시켜 개발 워크플로우의 신뢰성을 높여줍니다.
핵심 포인트
- Python DSL을 사용해 CI/CD 파이프라인 정의 가능
- 로컬 Docker 환경과 클라우드 러너에서 동일하게 실행
- 레이어 캐싱 및 DAG 병렬 처리가 내장되어 있음
Harmont이란 무엇인가?
Harmont는 Python으로 CI/CD 파이프라인을 정의하고, 단일 정의로부터 두 가지 방식으로 실행할 수 있게 해줍니다: Docker에서 자체 기계에 즉시 실행하거나 Harmont Cloud의 관리형 러너에서 실행하는 것입니다. 어떤 방식을 사용하든 동일한 파이프라인입니다. 따라서 로컬에서 디버깅한 실행 결과는 CI에서 배포되는 결과와 바이트 단위로 일치하기 때문에, 무엇이 깨지는지 알아내기 위해 임시 커밋을 계속 푸시할 필요가 없습니다. 각 단계는 내장된 캐싱, DAG 병렬 처리 및 일관된 환경을 갖춘 격리된 컨테이너에서 실행됩니다.
단일 --cloud 플래그로 파이프라인을 관리형 러너에 푸시할 수 있습니다.
팀들이 전환하는 이유:
- 파이프라인은 실제 코드입니다 — Python 또는 TypeScript를 사용하며, 에디터가 이미 제공하는 자동 완성 기능, 타입 및 추상화 기능을 활용할 수 있습니다.
- 로컬에서 실행합니다 —
hm run은 Docker 환경에서 로컬 머신에 실제 파이프라인을 실행하므로, 푸시하기 전에 실패를 확인할 수 있습니다. - …또는 클라우드에서 실행합니다 — 동일한 파이프라인이
hm run --cloud를 사용하여 Harmont Cloud의 관리형 러너에서 실행되며, 로컬 실행과 바이트 단위로 동일합니다. 여기에서 시작하세요. - DAG 기반 병렬 처리 — 독립적인 단계들이 동시에 실행됩니다.
hm이 의존성 그래프를 알아서 파악해 줍니다. - 자동 레이어 캐싱 — Docker 스냅샷은 여러 실행에 걸쳐 재사용되므로, 변경된 단계만 다시 실행합니다. 캐싱 기능이 기본적으로 작동합니다.
- 타입 지정 도구 체인(Typed toolchains) — Rust, Go, Python, JavaScript/TypeScript, C/C++, Zig, Elixir를 위한 1급 프리셋을 제공하며, 각각 설정, 빌드, 테스트, 린트 및 포맷팅 작업을 처리해 줍니다.
- Claude가 작성해 줍니다 —
hm init은 파이프라인을 작성하고 GitHub Actions를 마이그레이션하는 Claude Code 스킬을 설치합니다 (아래 참조).
빠른 시작(Quick Start)
hm 설치
curl -fsSL https://get.harmont.dev/install.sh | sh
또는 Cargo를 통해:
cargo install harmont-cli
30초 만에 시작하기: hm init
hm init
hm init은 템플릿으로부터 작동하는 .hm/pipeline.{py} 파일을 스캐폴딩하고, 파이프라인을 작성하고 유지 관리할 Claude Code 스킬 설치를 제안합니다. 실행한 후 메뉴에서 스택을 선택하거나 -t 플래그로 미리 템플릿 이름을 지정할 수 있습니다:
hm init -t rust # cmake · elixir · nextjs · js · rust · zig · python
그런 다음 실행합니다:
hm run
만약 레포지토리가 하나의 파이프라인만 선언하면, 슬러그는 선택 사항입니다. 그렇지 않은 경우 이름을 지정하세요: hm run ci.
클라우드(Cloud)의 경우, hm cloud login을 실행한 다음 hm run --cloud를 사용합니다. 동일한 파이프라인이 관리형 러너에서 실행됩니다. 아래 Cloud 섹션을 참조하세요.
또는 직접 작성하기
파이프라인은 그저 코드입니다. 이를 .hm/pipeline.py로 저장하세요:
import harmont as hm
from harmont.python import PythonToolchain
...
hm run ci
example projects에서 Rust, Go, Python, Elixir, Zig, C/C++, TypeScript, React, Next.js를 위한 관용적인(idiomatic) 파이프라인을 살펴보세요.
Claude가 CI 설정을 도와드립니다
hm init은 저장소에 세 가지 [Claude Code] 스킬을 설치할 수 있습니다. 이 스킬들은 파이프라인 작성 및 마이그레이션을 대화형 과정으로 바꿉니다:
| 스킬 | 기능 |
|---|---|
| write-pipeline | Claude에게 "CI를 설정해 줘"라고 요청하면, 클로드가 사용 중인 스택을 감지하고, 최신 Harmont 문서를 읽어 정확한 .hm/pipeline 파일을 작성합니다. |
| ... |
hm init # .github/workflows를 감지하여 convert-gha 기능을 제공합니다.
이미 파이프라인이 있고 스킬만 필요한가요? hm init을 다시 실행하세요. 템플릿 설치는 건너뛰고 스킬만 설치됩니다.
GitHub Actions에서 오신 경우?
마이그레이션은 쉬운 부분입니다. convert-gha 스킬은 모든 워크플로우를 읽어 자동으로 매핑해 드립니다:
actions/checkout→ 필요 없음 (소스는 항상 컨테이너 내에 있습니다)actions/setup-*→ 타입 지정된 툴체인으로 대체됩니다actions/cache→ 필요 없음 (Harmont이 도커 레이어를 자동으로 캐싱합니다)jobs.*.needs→ DAG(방향성 비순환 그래프)는 코드를 통해 파생됩니다runs-on→ 단계별로image=를 사용합니다 (기본 베이스 이미지는ubuntu:24.04입니다)
그 결과물은 CI에 배포되기 전에 로컬에서 실행해 볼 수 있는 파이프라인입니다.
작동 방식
자동 레이어 캐싱(Automatic layer caching). 모든 단계의 결과는 도커 스냅샷으로 커밋되며, 이 스냅샷은 해당 단계와 그 입력값으로부터 결정론적으로 키가 지정됩니다. 파이프라인을 재실행하면 입력값이 변경된 단계만 실제로 실행되고, 나머지 모든 것은 캐시에서 복원됩니다. DSL(Domain Specific Language) 내에서 단계별로 이를 조정할 수 있습니다:
hm.forever() # 입력값이 변경될 때까지 캐싱합니다
hm.ttl(timedelta(hours=6)) # 일정 시간 동안 캐싱합니다
hm.on_change("src/") # 이 경로들이 변경되면 재구축됩니다
DAG 병렬 처리(DAG parallelism). hm은 파이프라인에서 의존성 그래프(dependency graph)를 구축하고 독립적인 체인들을 동시에 실행합니다. 브랜치(branch)를 만들려면 .fork()를 사용하고, 합류(join)하려면 hm.wait()을 사용하세요. --parallelism N으로 동시성을 제어할 수 있으며 (기본값은 CPU 코어 수), 다음과 같이 사용할 수 있습니다.
실패 후에도 모든 것 실행하기. -k / --keep-going 옵션을 전달하면, 하나의 단계가 실패하더라도 독립적인 체인들은 계속 실행되어 한 번에 모든 실패를 확인할 수 있습니다. (이전에는 하나씩 확인해야 했습니다.)
hm run ci -k
타임아웃(Timeouts). 단일 단계 또는 전체 파이프라인에 시간 제한을 설정할 수 있습니다:
hm.timeout("5m", project.test()) # 개별 단계 (per-step)
@hm.pipeline("ci", timeout="30m") # 전체 파이프라인 (whole pipeline)
기계가 읽을 수 있는 출력(Machine-readable output). --format json은 표준 출력(stdout)에 빌드 이벤트(BuildEvent)를 줄마다 하나씩 방출합니다 (NDJSON 형식). 이 방식은 로컬에서 빌드를 실행하든 클라우드에서 실행하든 동일하며, 따라서 같은 래퍼 스크립트가 둘 다 파싱할 수 있습니다:
hm run ci --format json
진행률 표시줄(progress bar)보다 원시 로그를 선호합니까? --logs를 추가하세요.
클라우드 (Cloud)
Harmont Cloud는 관리형 러너(managed runners)에서 파이프라인을 실행합니다. 따라서 프로비저닝하거나 돌봐야 할 에그제큐터가 없습니다. hm run --cloud를 사용하면 **로컬 작업 디렉토리(local working tree)**를 커밋하거나 푸시하기 전에 제출합니다: CLI는 로컬에서 파이프라인을 렌더링하여 (따라서 손상된 DSL은 업로드되기 전에 빠르게 실패하며) 작업을 아카이브하고 (.gitignore를 존중하며, .git 폴더는 제거한 후) 이를 업로드하고 실시간 작업 로그를 스트리밍합니다.
계정 생성하기 후 다음 단계를 따르세요:
hm cloud login # 일회성 브라우저 로그인 (또는 --paste로 브라우저 없이 진행)
hm cloud org switch acme # 기본 조직(org)을 설정하여 --org를 생략할 수 있게 함
hm run --cloud # 현재 디렉토리를 클라우드에서 실행
로컬에서 할 수 있는 모든 작업이 클라우드에서도 작동합니다. 동일한 플래그, 동일한 --format json 이벤트 스트림을 사용합니다:
hm run --cloud --no-watch # 로그를 tailing하지 않고 제출하고 종료
hm run --cloud --org acme # 조직(org)을 명시적으로 지정
hm run --cloud --format json # 스크립팅을 위한 NDJSON BuildEvent 스트림
인증 (Authentication)
hm cloud login을 실행하면 루프백 리스너를 바인딩하고, app.harmont.dev/cli-login 페이지를 열며, 토큰을 ~/.config/hm/credentials.toml (모드 0600)에 저장합니다. 브라우저가 없나요? 이 경우 hm cloud login --paste를 사용하세요. CI 환경에서는 대신 토큰을 설정해야 합니다:
export HM_API_TOKEN=hm_live_... # 파일의 내용을 덮어씁니다 (takes precedence over the file)
hm run --cloud --org acme
Config
| File | Mode | Contents |
|---|---|---|
~/.config/hm/config.toml | 0644 | backend, [cloud] (org, api_url), [preferences] (format, auto_watch) |
~/.config/hm/credentials.toml | 0600 | API 기본 URL별로 키가 지정된 bearer tokens |
설정 계층은 기본값 → 사용자 설정 → 프로젝트 .hm/config.toml → 환경 변수 순서이므로, 리포지토리별 기본값을 커밋하면서도 로컬에서 이를 덮어쓸 수 있습니다. 환경 변수로 덮어쓰는 항목은 다음과 같습니다: HM_API_URL, HM_API_TOKEN.
CLI를 통한 빌드 관리
hm cloud whoami # 누가 나인가 (who am I)
hm cloud pipeline list # 활성 조직(active org)의 파이프라인 목록
hm cloud build list --pipeline ci # 파이프라인에 대한 빌드 목록
...
GitHub Actions
GitHub Actions를 떠날 준비가 되지 않았나요? Harmont 파이프라인을 GHA 내부에서 실행하고 Docker 이미지 캐싱을 무료로 자동화하세요. (떠날 준비가 되었나요? 위 convert-gha를 참조하세요.)
자동 Docker 이미지 캐싱 기능을 갖추고 GitHub Actions에서 파이프라인을 실행하려면 harmont-dev/actions-hm을 사용하세요:
name: CI
on: [push, pull_request]
...
이 액션은 hm을 설치하고 파이프라인을 실행하며, 이후 실행에서 변경되지 않은 단계를 건너뛰도록 GitHub Container Registry에 Docker 이미지를 캐싱합니다. 이 캐싱 기능은 자동으로 연결됩니다.
jobs:
lint:
runs-on: ubuntu-latest
...
- uses: harmont-dev/actions-hm@main
with:
pipeline: ci
...
전체 입력 참조(input reference), 서브 액션(sub-actions), 캐싱 세부 정보는 action repo를 확인하세요.
예시 (Examples)
examples/ 디렉토리에는 각 스택별로 완전하고 실행 가능한 파이프라인이 있습니다:
| Rust | Go | Python (uv) |
| ... | ||
사용하는 스택이 없으신가요? 툴체인(Toolchains)은 기본 단계(hm.sh(...))로부터 조합되므로, 컨테이너에서 실행되는 모든 것에 대한 파이프라인을 구축할 수 있습니다. |
문서 (Documentation)
전체 파이프라인 참조, 더 풍부한 예시 및 기타 정보는 docs를 확인하세요.
커뮤니티 (Community)
Harmont은 오픈 소스로 구축되었으며, API가 아직 변경 중인 동안 여러분의 피드백을 받고 싶습니다.
- Discord — discord.gg/hm-dev
- Slack — 워크스페이스 참여하기
- 이슈 (Issues) — github.com/harmont-dev/harmont-cli/issues
- 기여하기 (Contributing) — 시작하려면
CONTRIBUTING.md를 확인하세요.good first issue레이블이 지정된 이슈가 좋은 진입점입니다.
버그 파일을 제출하거나, 툴체인을 요청하거나, 무엇 때문에 흥미를 잃었는지 알려주세요. 모든 것이 도움이 됩니다.
라이선스 (License)
CLI는 다음 중 하나로 이중 라이선스를 적용받습니다:
- Apache License, Version 2.0 (
LICENSE-APACHE) - MIT license (
LICENSE-MIT)
동기 (Motivation)
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Claude Code Search의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기