가장 게으른 시니어처럼, AI가 코드를 덜 쓰게 만드는 Ponytail

가장 게으른 시니어처럼, AI가 코드를 덜 쓰게 만드는 Ponytail

July 3, 2026

저에겐 이런 선배가 없었습니다. 있었으면 했어요.
내가 밤새 붙잡고 짠 함수를 말없이 들여다보더니, 절반을 지우고 한 줄로 바꿔 놓고 가는 사람이요.
그 한 줄이 처음엔 좀 얄밉다가도, 며칠 지나면 왜 맞는지 알게 되는 그런 선배 말입니다.

Ponytail은 없던 그 선배를 AI 코딩 에이전트 안에 들여놓는 오픈소스 스킬입니다.
Dietrich Gebert가 만들었고 MIT 라이선스라 무료로 쓸 수 있어요.

![Ponytail의 GitHub 스타 히스토리 차트. 공개 직후부터 가파르게 상승한다][star-history-202676.png]

이 글에서는 Ponytail이 무엇이고, 어떤 원리로 AI가 코드를 덜 쓰게 만드는지, 그리고 직접 붙여서 써본 결과를 정리했습니다.
화려한 수치를 나열하기보다는, 디바운스 훅 하나를 직접 시켜본 전후 차이에서 출발했습니다.

간단한 걸 시켰는데 왜 이렇게 커질까요

바이브 코딩을 해보신 분이라면 아마 이 장면이 익숙하실 거예요.
간단한 걸 하나 부탁했는데, 에이전트가 유틸을 새 파일로 만들고, 제네릭을 붙이고, 정리(cleanup) 로직까지 얹으며 일을 키우는 상황이요.

입력값이 바뀔 때마다 검색 요청이 나가지 않도록 디바운스를 걸어 달라고 한 적이 있습니다.
보통의 에이전트한테 시키면 이렇게 흘러갑니다.

  • useDebounce 훅을 새 파일로 만들고
  • useRefuseEffect로 타이머를 직접 관리하고
  • 언마운트 정리 로직을 붙이고
  • 제네릭 타입까지 얹어 “재사용 가능하게” 다듬습니다

결국 두 줄로 끝날 일을 훅 하나로 부풀려 놓는 셈이에요.
문제는 이게 특정 모델의 실수가 아니라, 시키면 뭐든 만들어내는 게 에이전트의 기본 성향이라는 데 있습니다.
더 좋은 프롬프트를 준다고 저절로 고쳐지지 않아요.

만들기 전에, 안 만들어도 되는지부터 묻습니다

Ponytail이 하는 일은 생각보다 단순합니다.
에이전트가 코드를 쓰기 전에, 질문 몇 개를 반드시 통과하게 만드는 규칙을 심어 두는 거예요.
위에서부터 훑어 내려가다가 처음 “예”가 나오는 칸에서 멈춥니다.

  1. 이 기능이 정말 있어야 하나요. 아니라면 거기서 끝입니다.
  2. 이미 코드베이스에 있는 걸로 되나요. 그럼 그걸 재사용합니다.
  3. 표준 라이브러리로 되나요. 그럼 그걸 씁니다.
  4. 브라우저나 언어가 기본으로 주는 기능이 있나요. 그럼 그걸 씁니다.
  5. 이미 깔려 있는 의존성으로 되나요. 새로 설치하지 않습니다.
  6. 한 줄로 줄일 수 있나요. 그럼 한 줄로 끝냅니다.

여기까지 전부 아니어야 비로소 새 코드를 씁니다. 그것도 동작에 필요한 최소한까지만요.
이 사다리의 뿌리에는 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 말고도 붙일 수 있는 도구가 많습니다.

  • Codexcodex plugin marketplace add DietrichGebert/ponytail 뒤, 세션에서 /plugins로 설치
  • GitHub Copilot CLIcopilot plugin install ponytail@ponytail
  • Gemini CLI / Antigravitygemini extensions install https://github.com/DietrichGebert/ponytail (Antigravity는 agy plugin install)
  • OpenCode · Pi · Hermes 등도 어댑터로 지원합니다

도구별 최신 명령과 세부 사항은 저장소 README에 정리돼 있어요.
설치가 끝났는지 확인하려면 /ponytail-help로 명령 목록을 불러보면 됩니다.

정리하기

직접 며칠 써보니, Ponytail의 쓸모는 “코드를 쓰기 전에 한 번 멈춰 세운다”는 한 문장으로 모입니다.
디바운스 훅 같은 일상적인 유틸에서는 서른 줄이 두 줄이 될 만큼 효과가 분명했고, 그렇다고 안전이 걸린 자리까지 줄이지는 않도록 선을 그어 둔 점이 미덥게 느껴졌습니다.

물론 은탄환은 아닙니다.
추상화가 두껍게 쌓인 기존 코드베이스에서는 사다리만으로 판단하기 어려운 순간이 있고, 결국 맥락을 아는 건 사람 몫이니까요.
그래도 “일단 만들고 보는” AI의 기본값을 “먼저 안 만들 이유부터 찾는” 쪽으로 돌려놓는다는 점에서, 저는 이 스킬이 꽤 영리한 제약이라고 느꼈습니다.

밤새 짠 코드를 말없이 한 줄로 바꿔 놓고 가던 그 선배처럼, Ponytail도 매번 같은 걸 되묻습니다.
이거, 안 만들어도 되지 않아요? 가장 좋은 코드는, 애초에 쓰지 않은 코드니까요.

On this page