Claude Code를 쓰기 시작하면서 자동화 못하나 고민을 했다.
그 답을 찾기 위해 두 가지 방식을 직접 만들어서 써봤다. 실제 사용하고 ai 한테 물어본 결론은 한쪽은 특정 상황에서만 의미 있었고, 나머지는 팀 단위에서나 진짜 가치가 있었다.
질문 내용
워크플로우 개선 시도
각 개선 시도에 대해 상세하게 분석하고 내가 말한 장점과 문제점에 대해 상세히 분석
1. 코드가 있는경우 최대한 코드 전체를 분석한다.
2. 엔지니어링 기법을 사용한경우 해당 엔지니어링 기법에 대해 조사를 최대한 자세하게 한다.
3. 절대적으로 아래 시도 작업이 옳다는건 아니다. 실제 사실관계도 파악한다.
4. 관련 혹은 ai관련 최신 논문, 연구결과 등도 같이 비교 분석 한다.
5. 해당 모든 내용들을 문서로 정리한다.시도 작업
1. 노션, 피그마 링크를 ai 로 넘겨 interface, 설계, 프롬프트 생성해서 claude code 요청 - /Users/tpirates/workspace/workflow (local)
1.1 장점
GUI 로 지원 노션, 피그마 링크로 좀 더 편하다.
1.2 문제점
- 개발자가 직접 interface, 설계, 프롬프트 생성해서 하는게 더 명확하다.
- 실제 요구사항과 개발자가 원하는 방식을 맞추기 위해서는 많은 수정 요청을 한다.
- 수정 사항에 대해 매버 프롬프트로 다시 요청을 하는데 claude code로 하는거랑 뭐가 다른가.
- 하네스엔지니어링
2.1 장점
테스트로 좀 더 안정적인 개발 가능
2.2 문제점
- 기존에 레거시 프로젝트의 경우 테스트가 없는 경우도 있는데 이거는 커버가 안됨
- 실제 개발입장에서는 레거시 프로젝트를 유지보수 하는 경우가 많은데 해당 방식에 적용이 어려움
- ai skills interface 등록 - https://github.com/jaemyeong-hwnag/common-ai-skill
3.1 장점
기능만 명세하고 ai 가 직접 프로젝트에 맞는 구현을 개발
3.2 문제점
- 이게 진짜 효용성이 있는지 잘 모르겠다.
- 기능별로 너무 명확하게 한계가 있어 보인다.
Notion 백로그 URL을 넣으면 코드 스캐닝, 스펙 생성, 프롬프트 생성까지 자동으로 처리하고 Claude Code를 실행하는 파이프라인을 만들었다.
흐름은 이렇다:
Notion URL
→ 레포 코드 스캔 (메서드 시그니처만, 구현 코드 제외)
→ spec-draft (AI가 인터페이스 + 요구사항 초안)
→ [개발자가 아키텍처 결정 입력]
→ spec-refine
→ Claude Code 실행 프롬프트 생성
→ claude --dangerously-skip-permissions
논문도 뒤졌다. Lost-in-the-Middle 방지를 위해 핵심 제약을 메시지 하단에 반복하고, Claude는 XML이 YAML보다 성능이 높다는 연구(arXiv:2411.10541)를 반영해 AI 내부 통신 포맷을 잡았다. LLM-as-Judge도 달았다.
꽤 공들였는데 — 결과가 좋지 않았다.
기능 명세만 작성하면 AI가 프로젝트에 맞는 구현을 알아서 한다는 개념이다.
핵심은 이 철학이다:
"Skills define what must be achieved, never how. You are the implementation: read the skill → inspect this project → fulfill the contract"
Interface-First Development를 AI에 적용한 버전으로 보면 된다. 구현 방법을 지시하는 게 아니라 계약을 정의하면 AI가 프로젝트 맥락에 맞게 해석해서 구현한다.
실행 로그를 보면 솔직하게 드러난다.
날짜: 2026-04-02 하루
실행 횟수: 30회
실행 시간: 약 3시간 42분
spec.md 상태: human_review (완료 안 됨)
ai_prompts.md: 비어 있음
파이프라인이 human review 단계에서 멈췄다. spec-refine, 프롬프트 생성은 실행되지 않았다. 결국 직접 프롬프트를 써서 Claude Code를 30회 실행해 작업했다.
스펙 생성 레이어는 작동했지만 실제 작업에 쓰이지 않았다. 우회된 것이다.
워크플로우가 생성한 프롬프트의 제약 조건 섹션 내용:
스케쥴러는 없고 일단 api로 비즈니스 로직만 구현
외부 메시지 발송은 core에 구현
AI가 Notion에서 읽어온 게 아니라 개발자가 GUI에서 직접 타이핑한 것이다. Claude Code에 직접 쓰는 것과 차이가 없다.
Notion 백로그에는 비즈니스 언어로 쓰여 있었고, 어떤 패키지에 넣을지, 어떤 레이어에서 처리할지는 본인이 이미 알고 있었다. AI가 그걸 대신 결정해주는 게 아니라 본인이 입력한 것을 XML로 감싸줬을 뿐이다.
run_0의 첫 번째 오류:
RSA Private Key가 없어서 loadPrivateKey() IOException 발생.
signing-key에 Webhook secret을 넣었는데 이건 RSA 키가 아님.
이런 오류는 실행해봐야 안다. 스펙이 아무리 잘 만들어져도 잡을 수 없다. 30회 반복은 워크플로우 때문이 아니라 원래 일어날 수밖에 없는 디버깅 사이클이었다.
"Claude Code에 직접 오류 던져줘, 고쳐줘"가 똑같다.
워크플로우 코드 스캐너가 하는 일:
Claude Code의 Plan Mode에서 Claude Code가 직접 파일을 읽는 것이 중간 압축보다 정확하다. 시그니처만 추출하면 구현 맥락이 빠지지만, Claude Code는 실제 코드를 읽는다.
워크플로우가 Notion/Figma를 파싱해서 주입하는 작업:
claude mcp add notion
claude mcp add figma
이걸로 끝이다. Claude Code가 직접 Notion/Figma를 읽는다. 별도 서버, GUI, 파이프라인이 필요 없다.
완전히 쓸모없는 건 아니다. 아래 조건이 맞을 때는 워크플로우 서버가 실제로 차별점이 있다:
병렬 실행, 실행 이력 영속화, 스펙 버전 관리 — 이 세 가지가 필요한 상황이면 의미가 있다. 레포 하나에 혼자 작업하는 경우라면 CLI 직접 쓰는 게 더 빠르다.
레포: https://github.com/jaemyeong-hwnag/common-ai-skill
기존에 AI에게 뭔가를 시킬 때 보통 이렇게 된다. "이 파일에 이 메서드 추가해줘. 패턴은 이렇게 하고, 테스트는 이렇게 해줘." 구현 방법을 같이 설명한다.
스킬 방식은 반대다. "이 기능이 있어야 한다"는 계약만 정의하고, 어떻게 구현할지는 AI가 레포를 보고 판단하게 한다.
예를 들어 hexagonal-development 스킬은 이런 식이다:
모든 신규 기능은 헥사고날 아키텍처를 따른다.
Port 인터페이스를 먼저 정의하고, Adapter가 구현한다.
도메인 로직은 외부 의존성에 대해 알지 못한다.
이걸 한 번 등록해두면 AI가 코드를 추가할 때마다 프로젝트 구조를 스스로 파악해서 기존 패턴대로 맞춰준다. 매번 "우리 프로젝트는 헥사고날이야, 포트 먼저 만들어야 해"를 설명하지 않아도 된다.
delivery-workflow 스킬은 구현 → 테스트 → 커버리지 확인 → 커밋 사이클 전체를 하나의 명세로 정의한다. 이것도 한 번 등록하면 "구현하고 테스트까지"를 별도로 말하지 않아도 된다.
팀에서 쓸 때 실용성이 있다. 새 팀원이 합류했을 때 "이 스킬들 읽고 써"가 되고, 구현 방식에 대한 반복 설명을 줄일 수 있다.
쓰다 보면 이게 실제로 효과가 있는 건지 확신이 서지 않는다.
스킬이 마크다운 텍스트인 이상 AI가 해석하는 방식이 매번 다를 수 있다. 동일한 스킬 명세가 Claude 3에서 하던 것을 Claude 4에서 다르게 할 수 있다. 스킬 자체가 잘 작동하는지 테스트할 방법이 없다.
워크플로우 코드에서 내부 구현과 비교하면 차이가 분명하다. 내부에서 스킬은 Python 추상 클래스로 만들었다:
class Skill(ABC):
@abstractmethod
async def execute(self, input_: SkillInput) -> SkillOutput:
"""스킬 실행."""
타입 강제가 되고 단위 테스트를 붙일 수 있다. 반면 마크다운 명세는 AI가 읽고 해석하는 것이기 때문에 "이 스킬이 정확히 실행됐다"를 확인할 수단이 없다.
Chain-of-Thought 연구(Wei et al. 2022)에서도 비슷한 맥락이 있다. 같은 지시어도 모델 크기와 컨텍스트에 따라 일관성이 크게 달라진다. 스킬이 텍스트인 한 이 문제는 피하기 어렵다.
스킬들이 Best Practice를 전제로 만들어져 있어서, 그 전제가 맞지 않는 프로젝트에서는 오히려 방해가 된다.
hexagonal-development 스킬은 헥사고날 아키텍처를 가정한다. MVC 레거시 프로젝트에서 이 스킬을 쓰면 AI가 없던 레이어를 만들려고 한다.
coverage 스킬은 80% 커버리지를 목표로 강제한다. 레거시에서 80%는 비현실적인 숫자다.
finalize 스킬은 작업 후 자동으로 커밋까지 한다. 프로젝트마다 커밋 정책이 다른데 이게 충돌한다.
스킬이 Best Practice를 가정하는데, 실제 프로젝트는 Best Practice를 따르지 않는 경우가 많다. 그래서 기능별로 한계가 명확하다. 신규 프로젝트에서 아키텍처를 처음부터 잡는 경우에는 맞지만, 기존 프로젝트에 얹으려 하면 프로젝트마다 스킬을 별도로 만들어야 한다.
결국 혼자 쓰는 상황에서는 CLAUDE.md에 직접 프로젝트 컨벤션을 쓰는 것과 효과가 다르지 않다.
Claude Code 공식 문서에서 "single highest-leverage thing"이라고 표현한 것이다.
# 나쁜 요청
"알림 발송 기능 구현해줘"
# 좋은 요청
"POST /api/notify 구현해줘.
구현 후 curl -X POST http://localhost:8080/api/notify?date=2025-01-01
실행해서 HTTP 200 나오면 성공. 테스트도 작성하고 실행해."
Claude Code는 스스로 결과를 확인할 수 있을 때 훨씬 낫다.
매 실행마다 컨텍스트를 주입하는 것보다 레포 루트에 CLAUDE.md를 한 번 잘 써두는 게 낫다. 200줄 미만으로 유지하고, Claude가 코드에서 알 수 있는 것은 쓰지 않는다. 틀린 행동이 반복될 때만 추가한다.
# CLAUDE.md
## Architecture
- Hexagonal pattern (ports/adapters)
- 외부 API 호출은 core 패키지에서만
## Commands
- 빌드: ./gradlew build
- 테스트: ./gradlew test
## Do NOT
- git add -A 사용 금지
- .env 파일 수정 금지
- 기존 인터페이스 시그니처 변경 금지
테스트 없는 레거시에 AI가 코드를 추가하면 검증 방법이 없다. 이 경우 Characterization Test를 먼저 요청한다:
"YourService.findByDate() 메서드의 현재 동작을
Characterization Test로 캡처해줘.
실제 실행해서 현재 반환값을 확인하고,
그 값을 expected로 하는 테스트 작성.
내 의도가 아니라 현재 코드가 실제로 하는 일을 테스트해야 함."
Michael Feathers의 "Working Effectively with Legacy Code"에서 나온 패턴인데, AI 코딩에 그대로 쓸 수 있다.
| 상황 | 권장 방식 |
|---|---|
| 신규 기능 개발 | CLAUDE.md + Claude Code CLI 직접 |
| 레거시 유지보수 | Plan Mode + Characterization Test + 최소 변경 |
| 멀티 레포 대규모 작업 | MCP 연동 또는 워크플로우 서버 |
| 공통 | Human-in-the-Loop 필수 (AI solve rate 최대 62%) |
SWE-bench 기준으로 Claude 3.7 Sonnet이 ~62%를 해결한다. 38%는 항상 실패한다. 워크플로우가 좋든 나쁘든 AI가 완전히 틀릴 가능성은 항상 있다. 검증 단계와 사람 개입을 빼는 건 이 맥락에서 좋지 않다.