AI 코딩 에이전트에게 “캐시 좀 붙여줘”라고 하면, 열에 아홉은 TTL과 만료 정책과 인터페이스를 갖춘 캐시 클래스를 새로 짓는다. 정작 필요한 건 @lru_cache 한 줄이었는데. 이런 과잉엔지니어링을 막겠다고 나온 오픈소스가 ponytail이다. 이름값은 “50줄을 한 줄로 바꾸는, 세상 게으른 시니어 개발자”라는 캐릭터에서 온다.
기능 소개 글은 이미 많으니, 여기서는 조금 다른 각도로 본다. ponytail은 LLM을 단 한 번도 호출하지 않는다. 이게 이 블로그를 만들며 붙잡고 있는 원칙 — “MCP 서버는 모델을 부르지 않는다(무료 원칙)” — 과 정확히 같은 구조라서, 뜯어볼 가치가 있다.
결정 사다리라는 ‘룰’의 정체
ponytail이 하는 일은 단순하다. 에이전트가 코드를 쓰기 직전에 결정 사다리(decision ladder) 라는 체크리스트를 먼저 밟게 한다. 첫 번째로 걸리는 칸에서 멈춘다:
- 이게 존재할 필요가 있나? 투기적 필요면 건너뛴다 (YAGNI)
- 이 코드베이스에 이미 있나? 있으면 재사용한다
- 표준 라이브러리로 되나? 그걸 쓴다
- 플랫폼 네이티브 기능으로 되나? (
<input type="date">vs 달력 라이브러리) - 이미 깔린 의존성으로 되나? 새로 추가하지 않는다
- 한 줄로 되나? 한 줄로
- 그제서야: 동작하는 최소한의 코드
핵심은 이 사다리 전체가 그냥 텍스트라는 것이다. 모델을 추론시켜 만들어낸 게 아니라, 사람이 써 둔 규칙 문서다. ponytail은 이 문서를 매 요청의 컨텍스트에 끼워넣을 뿐이고, 실제로 사다리를 밟는 판단은 원래 있던 에이전트(Claude Code 같은)가 한다. 새 지능을 더하는 게 아니라, 이미 있는 지능의 기본값을 바꾸는 얇은 레이어다.
같은 룰, 세 가지 끼우는 자리
그럼 이 룰셋을 에이전트에게 어떻게 먹이느냐 — ponytail은 세 가지 형태로 같은 텍스트를 배포한다.
- skill:
SKILL.md한 장. 에이전트가 관련 작업을 인식하거나 사용자가/ponytail로 부르면 그 순간 룰이 로드된다. 필요할 때만 켜진다. - hook:
pre_llm_call같은 훅에 물려, 모델을 부르기 직전 매번 룰을 자동 주입한다. always-on. 사람이 부를 필요가 없는 대신 항상 켜져 있다. - MCP 서버: 룰셋을 MCP primitive로 노출해, MCP를 지원하는 아무 호스트에나 붙일 수 있게 한다.
셋은 “무엇을(같은 룰)“이 아니라 “어디에 끼우느냐”만 다르다. 이 분리가 깔끔한 이유는, 룰의 단일 출처를 하나 두고 배포 형태만 갈아끼우면 되기 때문이다. ponytail 코드도 실제로 하나의 룰 생성 함수를 skill·hook·MCP가 공유한다.
MCP는 왜 prompt와 tool 양쪽으로 노출하나
MCP 형태가 특히 재미있다. ponytail-mcp는 같은 룰셋을 prompt와 tool 두 primitive로 동시에 내보낸다. 왜 하나로 안 하고 둘 다일까? MCP의 3대 primitive를 떠올리면 답이 나온다 — 소비 주체가 다르다.
- prompt
ponytail: 사람이 슬래시 명령처럼 골라 부르는 재사용 대화 템플릿이다.lite/full/ultra모드를 인자로 받아 룰을 사용자 메시지로 꽂아준다. 사람이 능동적으로 켜는 통로. - tool
ponytail_instructions: 에이전트나 코드가 컨텍스트를 끌어올 때 부르는 통로다. 같은 텍스트에 더해{ mode, instructions }구조화 데이터까지 돌려줘, 프로그램이 파싱하기 좋다.
즉 같은 내용을 사람이 부르는 문과 기계가 부르는 문, 두 개로 낸 것이다. MCP Prompt로 워크플로를 패키징하던 것과 같은 발상인데, 여기서는 “워크플로” 자리에 “행동 규칙”이 들어갔다. LLM 호출이 없으니 이 서버를 굴리는 비용은 사실상 0이다. 룰 텍스트를 골라 되돌려주는 게 전부다.
그래서 나는 무엇을 붙였나
이 블로그 레포에 실제로 ponytail을 붙일 때, 나는 MCP도 hook도 아닌 skill 한 장만 골랐다. .claude/skills/ponytail/SKILL.md 파일 하나 복사가 끝이었다.
이유는 ponytail 자신의 사다리를 그대로 적용한 결과다. MCP 서버로 붙이면 프로세스를 하나 더 띄워야 하고(사다리 5번: 새 의존성), hook으로 붙이면 매 응답에 강제 주입되는 설정 변경이 필요하다(사다리 1번: 정말 항상 켜져 있어야 하나?). 반면 skill은 파일 한 장이고, 필요할 때 /ponytail로 부르면 된다. “안 만들어도 되는 프로세스는 안 띄운다” — 도구를 붙이는 방식 자체를 그 도구의 철학으로 결정한 셈이다.
ponytail이 알려주는 건 결국 이거다. 에이전트의 행동을 바꾸는 데 꼭 더 똑똑한 모델이나 더 무거운 인프라가 필요한 건 아니다. 잘 쓰인 룰 텍스트 한 장을, 알맞은 자리에 끼워넣는 것으로 충분할 때가 많다. 그리고 그 “끼워넣는 자리”를 표준화한 게 MCP의 prompt와 tool이다.
이 글에 대한 의견은 아래 댓글로 남겨주세요 (GitHub 계정 필요). 로그인 없이 남기고 싶다면