OpenSpec으로 시작해 본 스펙 주도 개발
최근 몇 달 동안 회사 사정으로 개발을 혼자 맡아야 했다. 방향을 잃지 않기 위해 명세서를 이정표로 삼았다. AI가 만든 초안을 다듬어 docs/ 디렉토리에 마크다운으로 쌓고, 그 문서를 기준으로 기능을 개발하고 검증했다. 리소스가 부족해 “당장 실행”이 우선이던 상황에서는 이 방식이 꽤 효율적이었고 결과도 나쁘지 않았다.
하지만 협업을 생각하면 기준이 달라진다. 개인의 작업 습관이 아니라, 팀이 공유할 수 있는 투명하고 객관적인 기준이 필요하다. “문서를 남기는 방식”을 넘어, 함께 일하기 위한 워크플로우를 다시 고민하게 됐다.
그러던 중 Claude Code for Designers: A Practical Guide 글을 읽고, 그 안에서 소개된 Get Shit Done (GSD)을 알게 되었다.
GSD: AI 에이전트를 위한 단계형 워크플로우
GSD는 AI 코딩 에이전트에게 단계별로 컨텍스트를 먹이면서 일을 시키는 프레임워크다.
기본 흐름은 다음과 같다.
- discuss → plan → execute → verify
- 각 단계의 산출물은 .planning/ 아래에 문서로 축적된다.
한계: 협업과 interrupt에 취약하다.
GSD는 한 사람이 discuss, plan, execute, verify를 순서대로 밟는 걸 전제로 설계됐다. 두 명이 동시에 서로 다른 단계를 작업하는 상황은 고려하지 않는다.
컨텍스트 엔지니어링이 "내 세션"에 묶여 있다는 점도 걸림돌이다. GSD의 핵심 강점인 플랜마다 새로운 컨텍스트를 부여하는 구조, 서브에이전트를 오케스트레이션하는 방식—이 모든 게 결국 한 사람의 Claude Code 세션 안에서 돌아가는 거다. 팀원 A가 짜놓은 플랜을 팀원 B가 이어받아 실행하는 식의 협업은 아직 매끄럽지 않다.
가장 번거로운 건 작업 도중 새로운 일이 끼어드는 상황이다. phase 1, 2, 3 순서로 로드맵을 짜고, 각 phase마다 discuss → plan → execute → verify를 밟아 나가는데, 긴급한 작업이 뚝 떨어지면 문제가 생긴다. insert-phase로 번호를 밀어넣고, 뒤쪽 phase를 전부 리넘버링해야 한다. 이미 plan까지 만들어둔 phase가 있다면? 앞에 뭔가 끼워넣는 순간 컨텍스트가 꼬일 수 있다. quick 모드로 ad-hoc 작업을 별도 트랙에서 돌리는 방법도 있긴 하다. 하지만 이건 메인 워크플로우 바깥에서 도는 거라, 전체 프로젝트 상태와 맞아떨어지는지는 결국 사용자가 직접 챙겨야 한다.
그래도 좋았던 점: discuss가 오판을 줄인다.
그럼에도 GSD에서 가장 마음에 든 건 discuss 단계였다. 프로젝트 레벨의 큰 명세(요구사항, 로드맵)는 이미 있는 상태에서, 각 phase를 구현하기 직전에 discuss가 돌아간다. 큰 그림은 있지만 세부 결정이 흐릿한 지점을 찾아서 “애매한 결정 지점(gray area)”을 꺼내고, 사용자가 선택하게 만든 뒤 해당 선택지를 깊게 파고든다. 이 단계 덕분에 내가 놓친 부분이 드러나는 경우가 많았고, 자연스럽게 신뢰도가 올라갔다.
GSD에서 gray area(애매한 결정지점)를 식별하는 방식
1단계: 코드베이스 살펴보기 (Scout codebase)
2단계: phase 분석 → gray area 뽑아내기 (여기가 핵심) phase 목표를 보고 "이건 어떤 종류의 기능인가"를 판단한다. 판단 기준이 문서에 명시되어 있다.
- 사용자가 보는 것 (UI) → 레이아웃, 밀도, 인터랙션, 상태
- 사용자가 호출하는 것 (API) → 응답, 에러, 인증, 버전
- 사용자가 실행하는 것 (CLI) → 출력 형식, 플래그, 모드, 에러 처리
- 사용자가 읽는 것 (콘텐츠) → 구조, 톤, 깊이, 흐름
- 정리되는 것 (구조화) → 기준, 그루핑, 네이밍, 예외
이 분류를 기반으로 해당 phase에 맞는 gray area를 3~4개 생성한다. 일반적인 카테고리가 아니라 그 phase에 특화된 구체적인 모호한 지점을 만들어야 한다고 명시되어 있다.
3단계: 사용자에게 선택하게 하기
4단계: 선택한 영역마다 깊이 파고들기
5단계: CONTEXT.md 작성
GSD는 솔로 개발자 워크플로우에 맞춰져 있다. 상태 관리가 단일 사용자 기준이라 협업에는 잘 맞지 않는다. 좀 더 간단하고 가벼운 걸 찾다가 OpenSpec을 발견했다.
OpenSpec: 변경을 독립 단위로 관리하는 스펙 문서 워크플로우
OpenSpec은 일을 “프로젝트”가 아니라 변경(change) 단위로 쪼개서 관리한다. 변경 하나가 생기면 openspec/changes/{id}/ 폴더가 만들어지고, 그 안에서 문서를 점점 구체화해 간다. 이때 문서가 단순 설명이 아니라, 다음 단계의 입력값으로 쓰인다.
기본 아티팩트는 네 가지다.
- proposal: 왜/무엇을 바꾸는지. 목표와 범위(스코프)를 잡는다.
- specs: 요구사항을 문장으로 고정한다. (MUST/SHOULD 같은 강도까지 포함)
- design: 어떻게 만들지. 구조, 인터페이스, 주요 결정 사항을 정리한다.
- tasks: 실제 작업 단위로 쪼개서 실행 순서와 체크리스트로 만든다.
스펙 문서 기반 워크플로우는 GSD에서 이미 경험했기 때문에, 자연스럽게 GSD와 비교하며 평가하게 된다.
OpenSpec에서 가장 눈에 띈 건 유연함이다. 각 변경사항을 독립된 폴더(openspec/changes/)로 관리하고, proposal → specs → design → tasks라는 artifact 체계를 쓴다. 아무 시점에나 artifact를 수정할 수 있어서, GSD처럼 phase 번호를 밀어넣고 리넘버링하는 번거로움이 없다.
도구를 가리지 않는 점도 좋았다. 20개 이상의 AI 코딩 도구를 지원하니, 팀에 특정 도구를 강제할 필요가 없다. 거기에 OpenSpec은 처음부터 브라운필드—이미 돌아가고 있는 기존 프로젝트에 얹는 상황—를 핵심 사용 사례로 설계했다고 강조한다. 실제로 기존 프로젝트에 도입하는 게 정말 간단했다.
내게는 이 정도의 단순함과 유연함이면 충분했다. 다만 GSD에서 썼던 discuss phase만큼은 붙이고 싶었다.
OpenSpec에 discuss 단계 붙이기: planning 전에 gray area를 탐색한다.
내가 원한 목표는 단순했다. 본격적인 planning(=design/tasks 확정)에 들어가기 전에 gray area를 정리하고 싶었다.
OpenSpec CLI에 기본으로 들어 있는 기능은 아니어서, 에이전트 레이어에 커스텀 명령을 추가하는 방식으로 해결했다.
- Claude에서는 .claude에 커스텀 slash command로 등록
- Codex에서는 .codex의 skill 프롬프트에 처리 규칙을 추가
둘 다 실제로 하는 일은 같다. openspec/changes/{id}/design.md의 GRAY-AREAS 섹션을 생성/갱신한다.
여기서 중요한 건, openspec discuss 같은 CLI 서브커맨드를 만든 게 아니라는 점이다. 사용자가 opsx:discuss {id}를 입력하면, 에이전트가 그 입력을 해석하고 문서를 갱신하도록 “규칙”을 준 구조다. 즉, CLI가 아니라 에이전트가 움직이는 방식이다.
동작 방식
- 사용자가 채팅에서 opsx:discuss {id}를 입력
- 에이전트 런타임이 이 입력을 OpenSpec 워크플로우로 라우팅
- 라우팅된 지시문(Claude command / Codex skill)에 따라
- change-id 해석
- 필요 시 openspec list --json 조회
- proposal.md, design.md, tasks.md 읽기
- design.md의 ## GRAY-AREAS 섹션 생성/갱신
- 결과 요약을 사용자에게 반환
정리하면, LLM이 “명령 문서에 적힌 절차”를 실행 계획으로 바꾸고 필요한 도구 호출을 수행하는 구조다.
써보면서 든 생각
스펙 문서는 확실한 기준점이 되었다. 개발하다가 가설이 틀린 걸 알게 되면 스펙을 크게 뜯어고쳐야 하는데, 예전처럼 에이전트랑 대화하면서 md를 자유롭게 쌓는 방식이면 대화 흐름에 끌려가서 쉽게 산으로 갔다. OpenSpec은 proposal → specs → design → tasks라는 틀이 있어서, 계획이 바뀌어도 그 틀로 돌아와 다시 정리하면 됐다. 덕분에 더 멀리 방황하지 않고 방향을 다시 잡을 수 있었다.
더 깊이 OpenSpec를 이해하기 위해 DeepWiki로 읽고 있다. 마크다운 설계도를 에이전트가 읽기 좋은 데이터로 정리하는 방식이나, RFC 2119 키워드(MUST, SHOULD, MAY)로 요구사항의 강도를 명확히 하는 방식 등 배울 게 많다.
앞으로 해볼 것
이 스펙 기반 개발 워크플로우에는 검증 단계가 있다. 다만 그 검증은 ‘명세가 규칙에 맞게 정리됐는지’, ‘서로 모순은 없는지’ 같은 문서 중심 검증에 가깝다. 기능이 실제로 동작하는지는 별개의 문제라서, 적용 이후에 사용자 워크플로우 기준으로 확인하는 단계가 꼭 필요하다.
그래서 다음에는 두 축을 보강하려고 한다.
첫째, discuss를 개선 가능한 루프로 만든다.
discuss 자체는 대체로 도움이 됐지만, 몇 번은 잘못된 판단을 걸러내지 못했다. 어차피 내가 커스텀으로 붙인 단계라 고치기 어렵지 않다. 중요한 건 “프롬프트를 한번 손보고 끝”이 아니라, 바꾼 뒤에 케이스를 모아보고 다시 조정하는 식으로 평가-개선 사이클을 워크플로우에 넣는 것이다. 상세한 방식은 진행하면서 정하되, 최소한 비교 가능한 형태로 결과를 남기고, 실패한 케이스가 다음 프롬프트에 반영되게 만들 생각이다.
둘째, 스펙 기반 개발에 E2E 검증 단계를 넣는다.
명세와 사용자 워크플로우를 기준으로 E2E(또는 통합) 테스트를 작성하고, opsx:apply 이후 이 테스트가 통과해야 완료로 치는 흐름을 만들고 싶다. 문서 정합성 검증(validate)과 코드 반영(apply)만으로는 “완료”를 선언하기 어렵고, 결국 동작 검증이 기준이 되어야 한다.