ETC
  • Review
  • Development

Clauvis 개발기

2026년 04월 10일

Clauvis

3월 말, 현업에서 AI와 함께 일하면서 반복되는 패턴들이 눈에 들어오기 시작했다. Jira에서 이슈를 가져오고, 브랜치를 만들고, 코드를 짜고, PR을 올리고, 다시 Jira에 반영하는. 매일 이 루프를 돌리면서 생각했다 — 이걸 정리해주고 대신 처리해주는 비서가 있으면 좋겠다고. 내가 직접 Jira를 들여다보지 않아도, 오늘 할 일을 정리해주고, 코드를 짜주고, PR까지 올려주는. 그런 데스크톱 앱 버전 비서를 만들고 싶었다. 그게 Clauvis의 시작이었다.

Clauvis라는 이름

처음 이름은 claude-harness였다. 기능적으로는 맞는 이름이었지만 제품명으로는 밋밋했다. Claude 전용이니까 Claude가 이름에 들어가되, 전체가 아닌 일부분만 — 그런 방향으로 고민하다가 Clauvis가 나왔다. Claude + Vis(ibility/Vision). 클로드의 시야, 클로드를 통해 바라보는 개발 세계라는 의미를 담았다.

만들어놓고 보니 Claude + Jarvis 같은 어감이라 꽤 마음에 들었다. AI 비서라는 지향점과도 잘 맞았고. 거기서 영감을 받아 클로버 모양의 로고까지 만들었다. 'Clau'의 발음에서 클로버(Clover)가 연상됐고, 네 잎 클로버의 행운이라는 상징도 나쁘지 않았다.

기술적으로는 Electron + React 19 기반 데스크톱 앱이다. 모든 데이터는 ~/.clauvis/에 로컬 저장하며 외부 서버 의존성이 없다. TanStack Router/Query, SQLite, shadcn/ui + Tailwind v4를 썼고, 디자인은 Linear와 Raycast에서 영감을 받아 근-블랙 다크 모드로 갔다.

speckit이라는 체계

AI와 빠르게 만들다 보면 "일단 만들고 보자"는 충동이 자꾸 올라온다. 그래서 개발에 speckit을 적용했다. GitHub에서 만든 Spec-Driven Development 툴킷으로, 명세를 먼저 작성하고 그 명세가 구현으로 이어지는 흐름을 강제하는 도구다.

Constitution(원칙 정의) → Specify(명세 작성) → Plan(계획 수립) → Tasks(태스크 분해) → Implement(구현)

이 흐름을 .claude/commands/에 커스텀 커맨드로 자동화했고, Clarify(질의응답), Analyze(코드 분석), Checklist(완료 검증) 단계를 추가해서 프로젝트에 맞게 확장했다. 각 기능은 번호가 부여된 브랜치로 관리했고, specs/에는 다수의 기능 명세가 쌓였다.

6대 헌법 원칙 중 가장 자주 소환된 건 "명세 없이 구현하지 않는다""단순함과 YAGNI"였다. speckit은 속도에 취해 방향을 잃지 않게 잡아주는 장치였다.

AI와의 개발에서 체계가 필요한 이유는 속도가 빠르기 때문이다. 빠른 만큼 방향이 틀어졌을 때의 대가도 크다.

기능이 기능을 낳다

처음부터 모든 기능을 계획한 게 아니다. 하나를 만들면 다음이 보이고, 그걸 만들면 또 다음이 보이는. 비서 앱이라는 컨셉이 있으니, "이것도 비서가 해주면 좋겠는데?"라는 생각이 자연스럽게 기능으로 이어졌다.

셸 하나에서

첫날은 기반 구축이었다. Turborepo 모노레포에 Electron + React 19 셸을 올렸다. TypeScript 확장자 에러, ESM에서의 require is not defined, __dirname is not defined — 전형적인 Electron + ESM 설정 문제들이 줄줄이 나왔고, 해결하는 데 생각보다 시간을 썼다.

셸이 돌아가자마자 shadcn/ui 기반 디자인 시스템을 구축했다. macOS 신호등 버튼이 콘텐츠와 겹치는 문제를 Slack 스타일 커스텀 타이틀바로 해결했는데, 이때부터 하나의 패턴이 자리잡았다. 픽셀 단위 디자인 피드백. pb-3pb-2.5pt-4px-2px-3px-3.5. 이런 조정이 11일 내내 이어졌다.

AI 오케스트레이션

셸 다음으로 온 건 AI 오케스트레이션이었다. Claude Code 에이전트를 팀으로 묶어 관리하는 기능. 사용자가 목적을 입력하면 AI가 적절한 에이전트 멤버와 역할을 추천해서 팀을 자동 구성하는 것까지 구상했다.

이 과정에서 첫 번째 큰 벽을 만났다. Claude Code가 구현 도중 계속 멈추는 현상. "왜 계속 멈춰?", "계속 진행해줘"를 반복해야 했다. AI와의 협업에서 가장 당황스러운 순간은 AI가 아무 말 없이 멈추는 순간이다.

Jira 태스크 매니저

비서 앱이라면 제일 먼저 해줘야 하는 건 오늘 뭘 해야 하는지 정리해주는 것이다. Jira 태스크 매니저가 그 역할이었다. Jira를 직접 보지 않고도 일일/주간/월간 작업 관리를 할 수 있게, Claude와 함께 태스크를 분류하고 분해하는 것이 목표였다.

기능적으로 가장 야심찬 부분이자, 동시에 가장 고통스러운 부분이었다. No valid JSON found, Unexpected token '/' — JSON 파싱 이슈가 반복적으로 터졌다. Jira MCP 도구 호출 디버깅에만 여러 세션을 쏟았다. UI 쪽도 만만치 않았다. 스크롤이 안 되고, 사이드 패널 높이가 탭 아래로 제한되고, 네이티브 스크롤바가 "디자인을 망친다"며 커스텀 스크롤바를 요청하고. 체크박스 일괄 처리 시 헤더바가 나타나서 레이아웃이 시프트되는 문제까지.

이때 하나 깨달았다. Jira 같은 외부 시스템 연동은 순수한 UI 구현과는 복잡도 자체가 다르다. 데이터 포맷 불일치, 상태 동기화 타이밍, 로컬과 원격의 충돌 — 이런 건 AI가 한 번에 해결해주지 못하는 영역이었다.

Executor

비서가 할 일을 정리해줬으면, 다음은 직접 해주는 것이다. Executor는 AI로 태스크를 실행하는 기능이었다. 실행 버튼을 누르면 브랜치와 worktree를 설정하고, 실행 계획을 리포트로 생성하고, 확인 후 실행하는 파이프라인.

여기서 가장 많은 이슈가 터졌다. worktree 관리 실패, 경로 해석 오류, 프로세스 스폰 에러, 플랜 생성 타임아웃, 앱 프리징까지. "커서가 로딩 커서로 바뀌고 앱 전체가 제어 불가"한 상황도 겪었다.

에러 핸들링 요구도 점점 구체적이 됐다. PR 생성 실패 시 PR만 재시도, 재시도 시 어떤 단계부터인지 다이얼로그 표시, 실패 시 토스트와 히스토리에서 선택 가능하게, 실시간 로그 표시. 결국 병렬 실행을 직렬 큐로 바꾸고, 529 API Overloaded 재시도 로직을 넣고, worktree 자동 삭제를 구현했다.

Executor는 AI 자동화의 이상과 현실 사이 거리를 가장 적나라하게 보여준 기능이었다.

그 밖의 것들

이 외에도 많은 게 11일 사이에 일어났다. n8n 스타일 노드 에디터를 지향한 루틴 기능, Linear + Raycast 영감의 전면 디자인 오버홀, 태스크 히스토리 기반 이력서 빌더, 스마트 리포트, Git 브랜치 매니저.

가장 재밌었던 건 Nest — 게이미피케이션 탭이었다. Claude 사용량을 추적하고 포인트로 알을 구매해서 부화시키는 다마고치 컨셉. 12간지 동물로 시작했다가 픽셀 아트로 전환, 다시 음식 테마로 피봇했고, 레어 티어에 뚝배기와 버터떡까지 추가하려 했지만 — 결국 "Soon"으로 보류.

개발 막바지에는 멀티 에이전트 팀 실험도 했다. 기획자, 냉철한 리뷰어, 관대한 리뷰어, 구현자, QA — 5개의 에이전트가 역할을 나눠 기능 기획부터 구현까지를 자동화하는 시도였다. 냉철한 리뷰어가 "전체 루프 접근은 과도한 범위이며, 실제로 필요한 건 3개의 누락된 함수 호출뿐"이라고 지적한 건 인상적이었다. AI가 AI의 범위 초과를 교정하는 장면.

새 PC로 이전한 뒤의 3일 집중 스프린트(4월 8~10일)에서는 다수의 커밋과 세션, 기능과 개선이 쏟아졌다. stories와 tasks를 issues 단일 테이블로 통합한 아키텍처 결정, 하드코딩된 영어 상태명을 한국어 Jira와 호환시키기 위한 상태 캐싱, 사이드바 컴파운드 컴포넌트 패턴 도입 — 도구가 가장 빠르게 자라난 시기였다.

자주 부딪힌 것들

11일간 가장 많이 했던 교정은 간격과 정렬이었다. 패딩, 마진, 수직 정렬, gap 값에 대한 픽셀 단위 피드백이 압도적으로 많았고, 그 다음이 레이아웃 깨짐, 상태 관리 버그, 일관성 없는 디자인 순.

하지만 가장 근본적인 교정은 따로 있었다.

"단순하게 유지하고 범위를 정확히 지켜라."

이 메시지가 반복적으로 나타났다. 불필요한 설정 파일 생성 금지, 인라인 값 사용 권장, 요청한 페이지에만 변경사항 적용, 이미 있는 것을 확인하고 재사용. AI는 종종 "더 해주겠다"는 좋은 의도로 범위를 벗어났고, 그때마다 다시 끌어와야 했다.

반복된 좌절 포인트도 있었다. Claude Code가 구현 중간에 멈추는 현상, Jira Sync에서 로컬 전용 필드가 덮어쓰여지는 버그 — 이건 가장 집요하게 돌아왔다. 529 API Overloaded 에러는 외부 의존성이라 어쩔 수 없었고, 복잡한 state에 연결된 폼의 입력 지연도 끝까지 따라다녔다.

이런 벽들을 마주하면서 느낀 건, AI 협업의 한계는 AI의 능력보다 시스템의 복잡도에서 온다는 것이었다. 코드 생성 자체는 잘 해냈다. 문제는 외부 시스템 연동, 상태 동기화, 에러 핸들링 — 코드 바깥의 복잡도였다.

큐리어스에 써보다

Clauvis 개발에서 가장 재밌는 점은 그 재귀성이다. AI 도구를 만드는 데 AI를 사용했고, 만들어진 도구로 다시 실제 프로젝트를 개발했다.

큐리어스 — Flask에서 Next.js로 마이그레이션 중인 멤버십 커뮤니티 플랫폼에 Clauvis를 실전 투입했다. 26개 이상의 Jira 태스크를 actionable, blocked, other로 자동 분류하고, 구현 중심의 마크다운으로 이슈 설명을 자동 생성했다. 프롬프트도 진화했다 — 초기 범용 프롬프트에서 "동일 언어, 1500자 이하, Context/Implementation/Done-When 구조"의 최적화된 형태로.

실제 실행된 태스크도 있었다. 커뮤니티 글 작성 시 Slack 알림 미발송 수정, 모바일 홈 상단 검색바 추가. 이 과정에서도 동일한 피드백 패턴이 나타났다. "환경변수는 이미 있어", "검색 결과 페이지는 이미 있을 텐데 확인해봐" — 범위를 지키고 이미 있는 것을 확인하라는 교훈은 도구를 만들 때나 도구로 만들 때나 같았다.

개발 과정에서 식별된 반복 패턴들이 이 재귀성을 보여준다.

  1. Commit-Push-PR Update — 15회 이상
  2. Jira QA 태스크 일괄 상태 변경 — 5회 이상
  3. Figma 디자인 구현 + QA — 10회 이상
  4. E2E 테스트 시나리오 생성/실행 — 6회 이상
  5. API 스키마 동기화 + 배포 — 4회 이상

이 반복 패턴들이 Clauvis의 루틴/자동화 기능과 Executor의 존재 이유다. 만들면서 느낀 불편함이 기능이 되고, 그 기능을 쓰면서 다시 다음 불편함이 보이는. 비서 앱을 만들면서 비서가 필요한 순간을 계속 발견한 셈이다.

돌아보며

11일. 수많은 기능 스펙. 셀 수 없는 Claude Code 대화 세션. 숫자만 보면 그럴듯하지만, 솔직히 그 안에는 반복된 좌절과 교정의 시간이 더 많았다.

Clauvis를 만들면서 배운 건 결국 하나다. AI 코파일럿과의 개발은 "코드를 대신 짜주는 것"이 아니라 "방향을 잡아주고, 범위를 통제하고, 디테일을 교정하는" 지속적인 대화라는 것. speckit이라는 체계를 만든 이유도, 6대 헌법을 정한 이유도, 결국 이 대화의 품질을 높이기 위해서였다.

그리고 하나 더 — 도구는 쓰면서 자란다. 처음부터 완벽한 설계를 가지고 시작한 게 아니다. 셸 하나에서 시작해서, 쓰면서 부족한 것을 발견하고, 발견한 것을 채우고, 채운 것을 다시 쓰면서 다음을 발견하는. 그 반복이 11일간 이어진 것이고, 그 결과가 Clauvis다.

AI와의 개발은 속도의 게임이 아니라 대화의 게임이다.