저에겐 이런 선배가 없었습니다. 있었으면 했어요.
내가 밤새 붙잡고 짠 함수를 말없이 들여다보더니, 절반을 지우고 한 줄로 바꿔 놓고 가는 사람이요.
그 한 줄이 처음엔 좀 얄밉다가도, 며칠 지나면 왜 맞는지 알게 되는 그런 선배 말입니다.
Ponytail은 없던 그 선배를 AI 코딩 에이전트 안에 들여놓는 오픈소스 스킬입니다.
Dietrich Gebert가 만들었고 MIT 라이선스라 무료로 쓸 수 있어요.
![Ponytail의 GitHub 스타 히스토리 차트. 공개 직후부터 가파르게 상승한다][star-history-202676.png]
이 글에서는 Ponytail이 무엇이고, 어떤 원리로 AI가 코드를 덜 쓰게 만드는지, 그리고 직접 붙여서 써본 결과를 정리했습니다.
화려한 수치를 나열하기보다는, 디바운스 훅 하나를 직접 시켜본 전후 차이에서 출발했습니다.
간단한 걸 시켰는데 왜 이렇게 커질까요
바이브 코딩을 해보신 분이라면 아마 이 장면이 익숙하실 거예요.
간단한 걸 하나 부탁했는데, 에이전트가 유틸을 새 파일로 만들고, 제네릭을 붙이고, 정리(cleanup) 로직까지 얹으며 일을 키우는 상황이요.
입력값이 바뀔 때마다 검색 요청이 나가지 않도록 디바운스를 걸어 달라고 한 적이 있습니다.
보통의 에이전트한테 시키면 이렇게 흘러갑니다.
useDebounce훅을 새 파일로 만들고useRef와useEffect로 타이머를 직접 관리하고- 언마운트 정리 로직을 붙이고
- 제네릭 타입까지 얹어 “재사용 가능하게” 다듬습니다
결국 두 줄로 끝날 일을 훅 하나로 부풀려 놓는 셈이에요.
문제는 이게 특정 모델의 실수가 아니라, 시키면 뭐든 만들어내는 게 에이전트의 기본 성향이라는 데 있습니다.
더 좋은 프롬프트를 준다고 저절로 고쳐지지 않아요.
만들기 전에, 안 만들어도 되는지부터 묻습니다
Ponytail이 하는 일은 생각보다 단순합니다.
에이전트가 코드를 쓰기 전에, 질문 몇 개를 반드시 통과하게 만드는 규칙을 심어 두는 거예요.
위에서부터 훑어 내려가다가 처음 “예”가 나오는 칸에서 멈춥니다.
- 이 기능이 정말 있어야 하나요. 아니라면 거기서 끝입니다.
- 이미 코드베이스에 있는 걸로 되나요. 그럼 그걸 재사용합니다.
- 표준 라이브러리로 되나요. 그럼 그걸 씁니다.
- 브라우저나 언어가 기본으로 주는 기능이 있나요. 그럼 그걸 씁니다.
- 이미 깔려 있는 의존성으로 되나요. 새로 설치하지 않습니다.
- 한 줄로 줄일 수 있나요. 그럼 한 줄로 끝냅니다.
여기까지 전부 아니어야 비로소 새 코드를 씁니다. 그것도 동작에 필요한 최소한까지만요.
이 사다리의 뿌리에는 YAGNI라는 오래된 격언이 있습니다.
YAGNI는 “You Aren’t Gonna Need It”, 지금 당장 쓰지 않을 기능을 미리 만들지 말라는 뜻입니다.
보통은 삽질을 몇 번 겪고 나서야 몸에 붙는 감각이죠.
Ponytail은 이 감각을 사람이 매번 상기시키지 않아도 되도록, 에이전트가 알아서 지킬 규칙으로 바꿔 놓았습니다.
말로만 들으면 그럴싸하니, 저도 반신반의하면서 직접 붙여 봤습니다. 같은 요청을 두 번 시켜 보기로 했어요.
Ponytail을 끄고 Claude에 “검색 입력에 디바운스를 걸어 줘”라고 했더니, 이런 커스텀 훅이 나왔습니다.
import { useCallback, useEffect, useRef } from 'react';
export function useDebounce<T extends (...args: any[]) => void>(
callback: T,
delay: number
) {
const timer = useRef<ReturnType<typeof setTimeout>>();
useEffect(() => {
return () => {
if (timer.current) clearTimeout(timer.current);
};
}, []);
return useCallback(
(...args: Parameters<T>) => {
if (timer.current) clearTimeout(timer.current);
timer.current = setTimeout(() => callback(...args), delay);
},
[callback, delay]
);
}틀린 코드는 아니에요. 다만 이 프로젝트엔 이미 es-toolkit이 깔려 있었습니다.
같은 요청을 Ponytail을 켜고 다시 시켰더니, 답이 이렇게 돌아왔습니다.
import { debounce } from 'es-toolkit';
const search = debounce(onSearch, 300);서른 줄짜리 훅이 두 줄이 됐어요.
이미 있는 걸 새로 짜지 않는다는, 그 한 칸을 먼저 물었을 뿐입니다.
저는 이 지점에서 이 스킬이 왜 그렇게 빨리 별을 모았는지 조금 이해가 됐습니다.
저 혼자만의 우연은 아니었어요.
만든 사람이 공개한 벤치마크에서도, 같은 작업을 Haiku·Sonnet·Opus 세 모델로 돌렸을 때 스킬을 안 썼을 때보다 코드 줄 수가 눈에 띄게 줄었습니다.
게으르되, 부주의하진 않습니다
여기까지 들으면 슬슬 불안해집니다. 무작정 코드만 줄이다가 정작 중요한 걸 빠뜨리면 어쩌나 싶은 거죠.
저도 그게 제일 걱정이었는데, Ponytail은 줄여도 되는 자리와 절대 손대면 안 되는 자리를 갈라 놓았습니다.
게을러도 절대 아끼지 않는 항목이 규칙에 못 박혀 있어요.
- 외부에서 들어오는 입력값 검증
- 데이터가 날아가는 걸 막는 에러 처리
- 보안
- 접근성 기본
- 사용자가 분명히 요청한 기능
이 다섯 자리에는 코드를 아끼지 않습니다.
표준 라이브러리 안에서 길이가 비슷한 두 방법을 두고 고를 때도, 더 짧은 쪽이 아니라 엣지 케이스를 놓치지 않는 쪽으로 손이 가고요.
짧게 쓰는 것과 허술하게 쓰는 건 다르다는 원칙이 밑에 깔려 있는 겁니다.
그래서 “선행 실행(leading edge)이나 취소 기능이 꼭 필요하다”고 명확히 말하면, 그때는 두 줄이 아니라 제대로 된 구현을 만들어 줍니다.
한 가지 장치가 더 있습니다.
일부러 단순하게 처리한 자리에는 // ponytail: 주석을 남겨 둡니다.
지금은 간단히 넘어갔지만 나중에 무너질 수 있는 약점이 있다면, 그 한계와 보강 경로를 주석으로 적어 두는 식이에요.
// ponytail: 인메모리 Map이라 서버 인스턴스가 늘면 안 맞습니다. 공유가 필요하면 Redis로.
const seen = new Map<string, number>();이 주석들은 /ponytail-debt 명령으로 한데 모아 부채 목록으로 뽑을 수 있습니다.
“나중에 하자”가 슬그머니 “영영 안 함”이 되는 걸 막아 두는 셈이죠.
저는 이 부분이 단순한 코드 다이어트 도구와 Ponytail을 가르는 지점이라고 봤습니다.
강도는 세 단계로 고릅니다
원리를 봤으니 실제로 어떻게 쓰는지도 짚어 볼게요.
Ponytail은 게으름의 세기를 세 단계로 고를 수 있습니다.
- lite — 시킨 대로 만들되, 더 게으른 방법이 있으면 알려주는 정도
- full — 기본값. 사다리를 강제로 적용해 최단 코드로 밀어붙입니다
- ultra — “이 기능 자체가 진짜 필요한가요”라며 요구사항까지 되묻습니다
과설계가 심한 코드베이스를 손볼 때는 ultra가, 평소 작업에는 full이 무난했습니다.
설치를 마친 뒤 /ponytail full이나 /ponytail ultra처럼 언제든 바꿀 수 있고, 잠시 꺼두고 싶으면 /ponytail off를 쓰면 됩니다.
설치하기
저는 Claude Code에 붙였습니다.
CLI라면 아래 두 명령을 각각 따로 보내면 됩니다. 한 번에 이어 붙여 보내면 설치가 안 걸리더라고요.
/plugin marketplace add DietrichGebert/ponytail
/plugin install ponytail@ponytail데스크톱 앱에는 /plugin 명령이 없어서 UI로 넣습니다.
Customize → 개인 플러그인 옆 + → Create plugin and add marketplace → Add from repository 순서로 저장소 URL을 입력하면 돼요.
한 가지 짚어둘 점이 있습니다.
Claude Code와 Codex 플러그인은 작은 Node.js 훅을 돌리기 때문에, node가 PATH에 잡혀 있어야 “항상 켜짐” 활성화가 조용히 동작합니다.
없어도 스킬 자체는 작동하지만, 프롬프트마다 활성화 메시지가 뜰 수 있어요.
Claude Code 말고도 붙일 수 있는 도구가 많습니다.
- Codex —
codex plugin marketplace add DietrichGebert/ponytail뒤, 세션에서/plugins로 설치 - GitHub Copilot CLI —
copilot plugin install ponytail@ponytail - Gemini CLI / Antigravity —
gemini extensions install https://github.com/DietrichGebert/ponytail(Antigravity는agy plugin install) - OpenCode · Pi · Hermes 등도 어댑터로 지원합니다
도구별 최신 명령과 세부 사항은 저장소 README에 정리돼 있어요.
설치가 끝났는지 확인하려면 /ponytail-help로 명령 목록을 불러보면 됩니다.
정리하기
직접 며칠 써보니, Ponytail의 쓸모는 “코드를 쓰기 전에 한 번 멈춰 세운다”는 한 문장으로 모입니다.
디바운스 훅 같은 일상적인 유틸에서는 서른 줄이 두 줄이 될 만큼 효과가 분명했고, 그렇다고 안전이 걸린 자리까지 줄이지는 않도록 선을 그어 둔 점이 미덥게 느껴졌습니다.
물론 은탄환은 아닙니다.
추상화가 두껍게 쌓인 기존 코드베이스에서는 사다리만으로 판단하기 어려운 순간이 있고, 결국 맥락을 아는 건 사람 몫이니까요.
그래도 “일단 만들고 보는” AI의 기본값을 “먼저 안 만들 이유부터 찾는” 쪽으로 돌려놓는다는 점에서, 저는 이 스킬이 꽤 영리한 제약이라고 느꼈습니다.
밤새 짠 코드를 말없이 한 줄로 바꿔 놓고 가던 그 선배처럼, Ponytail도 매번 같은 걸 되묻습니다.
이거, 안 만들어도 되지 않아요? 가장 좋은 코드는, 애초에 쓰지 않은 코드니까요.