3줄 요약
- tamaratran이 2026년 9월 17일에 공개한 저장소다. npm 패키지인 동시에 Claude Code 플러그인이고, 컴팩션이 일어날 때 지난 대화를 요약하는 대신 도구 호출과 도구 결과만 골라서 지운다.
- 무엇을 지울지는 TypeSafe의 판단용 모델 Jev가 정한다. 호출 하나마다 두 질문의 답을 확률로 받고, 기준값을 넘으면 원문 그대로 두고 넘지 못하면 앞 300자만 남기거나 호출까지 함께 삭제한다. 사용자와 어시스턴트가 쓴 글은 한 글자도 바뀌지 않는다.
- Jev 호출이 실패하거나 압축 비율이 기준에 못 미치면 Claude Code의 내장 요약으로 되돌아간다. 저자도 README에서, 이 확률은 지워도 안전하다는 증명이 아니라고 스스로 밝혔다.
요약을 만들지 않는 압축
이 저장소가 무엇을 문제로 보는지부터 옮긴다. README의 설명은 이렇다.
대부분의 컨텍스트 압축은 LLM에게 지난 대화를 요약하라고 시킨다. 요약에는 손실이 있다. 파일 경로, 정확한 오류 메시지, 제약 조건, 명령어는 나중에 필요해지는 순간에는 이미 사라져 있을 수 있다.
그래서 이 라이브러리는 어떤 문장도 고쳐 쓰지 않는다. Jev가 더는 필요 없다고 판정한 도구 호출과 도구 결과를 삭제할 뿐이고, 그 판정을 물을 때는 대화 전체를 보여 준다. 사용자와 어시스턴트의 텍스트는 원문 그대로, 순서도 그대로 남는다.
저장소는 두 가지 역할을 겸한다. src/는 fast-jev-compaction이라는 이름의 npm 라이브러리다.1 hooks/와 .claude-plugin/은 플러그인이다. 그 라이브러리를 불러다 Claude Code의 내장 컴팩션 요약을 원본 메시지로 갈아 끼운다. 라이선스는 MIT, 언어는 TypeScript이며 Node 18 이상을 요구한다.

이 저장소가 만들어진 속도 역시 평범하지 않다. 첫 커밋과 마지막 커밋은 모두 2026년 9월 17일에 찍혔다. 서른 개 남짓한 커밋은 대부분 devin/1789… 꼴의 브랜치에서 나왔다. 커밋 기록만 놓고 보면 코딩 에이전트가 하루 만에 조립해 낸 저장소다. 그런데도 공개 나흘째인 9월 21일 기준으로 별 5,090개와 포크 281개를 받았다.2
동작 순서
README가 일곱 단계로 정리해 둔 흐름을 그대로 옮긴다.
- 각
tool_use를tool_use_id가 같은tool_result와 짝짓는다. 첫 메시지에 든 호출과 최근preserveRecentMessages개 메시지에 든 호출은 고정되어 후보에서 빠진다. - Jev에게 보내는 상태(state)는 지금까지의 대화 전체를 오래된 순서로 담되, 모든 도구 결과를
ok, 4213 chars (omitted)같은 짧은 메모로 바꾼 것이다. 도구 입력과 텍스트는 그대로 들어가고 요약은 일절 없다. - 그 상태를
maxStateTokens(기본 25,000) 안에 맞춘다. 줄이는 방법은 여러 단계이고, 앞 단계만으로 예산을 맞추지 못할 때에만 다음 단계로 넘어간다. - 고정되지 않은 호출마다 Jev에게
noul질문을 두 개 던진다.noul은 참일 확률 하나만 돌려주는 질문 형식이다. 호출 자체가 남아야 하는지, 그리고 결과 전문이 원문 그대로 남아야 하는지를 따로 묻는다. - 상태와 질문을 합친 크기가
maxRequestTokens를 넘지 않도록 질문을 여러 차례에 걸쳐 보낸다. 기본값은 30,000이고, Jev의 요청 한도 32,000보다 낮게 잡아 둔 값이다. 같은 상태 전문을 요청마다 다시 보내고, 요청은 동시에 실행한 뒤 답을 합친다. - 호출별 판정을
keepThreshold와 견준다. - 메시지 목록을 다시 만든다. 내용이 전부 사라진 메시지는 없앤다. 손대지 않은 메시지는 들어온 객체 그대로 돌려준다. 호출 없이 결과만 남는 경우는 만들지 않는다.
Jev 요청이 실패하거나 답이 형식에 맞지 않으면 라이브러리는 예외를 던진다. 키가 없거나 이력을 예산 안에 넣지 못한 경우도 마찬가지다. 무엇으로 대신할지는 호출한 쪽이 정한다.
Jev에게 보내는 상태를 예산 안에 넣는 법
3단계에서 상태를 줄이는 방식이 이 라이브러리에서 가장 손이 많이 간 부분이다. fitState는 아래 순서를 차례로 적용한다. 상태가 예산 안에 들어오면 그 즉시 멈추고, 어느 단계에서 멈췄는지를 stats.stateStage에 기록한다.
| 순서 | 줄이는 방법 |
|---|---|
| 1 | 도구 입력 JSON을 1,000자로 자른다 |
| 2 | 같은 입력을 200자로 자른다 |
| 3 | 같은 입력을 60자로 자른다 |
| 4 | 긴 텍스트를 머리 400자와 꼬리 150자만 남기고 줄인다. 고정되지 않은 메시지부터 손대고 고정된 메시지는 맨 뒤로 미룬다 |
| 5 | 오래된 비고정 메시지의 본문을 [… N chars omitted …] 한 줄로 바꾼다 |
| 6 | 오래된 도구 호출을 t12 Read file_path=src/a.ts → ok 480ch 같은 한 줄로 줄인다 |
| 7 | 호출이 없는 오래된 메시지를 아예 뺀다 |
| 8 | 연달아 붙은 호출 전용 메시지들을 한 항목으로 합친다 |
여기까지 해도 예산을 못 맞추면 컴팩션은 예외를 던지고 끝난다.

토큰은 토크나이저 없이 센다. 알파벳 단어는 여섯 글자마다 1토큰, 숫자는 한 자리마다 0.5토큰, 나머지 기호는 0.9토큰으로 계산한다. 주석에 따르면 이 방식은 Jev가 실제로 보고한 사용량보다 2%에서 18% 크게 나오도록 맞춰 둔 값이다. 문자수를 상수로 나눠 어림하는 흔한 방식은 JSON이 많은 상태에서 최대 40%까지 적게 센다고 한다.
상태에는 고정된 안내문 한 단락이 함께 들어간다. 판정자에게 지금 무슨 일이 벌어지는지 알려 주는 글이다.
코딩 어시스턴트의 대화를 압축해 컨텍스트를 비우는 중이다.
history는 지금까지의 대화 전체이며 오래된 것이 먼저 온다. 도구 출력은 짧은result메모로 대체되어 있고 긴 텍스트는 줄여 놓았을 수 있다. 각 질문은 도구 호출 하나 또는 그 호출의 출력 전문이 여전히 원문 그대로 남아 있어야 하는지를 묻는다. 남기지 않은 것은 영구히 삭제되지만, 어시스턴트는 언제든 도구를 다시 실행하거나 파일을 다시 읽을 수 있다.
두 개의 질문과 세 갈래 판정
호출 하나에 대해 Jev가 받는 질문은 다음 두 개다.
도구 호출
t7(Read)이 이력에 남아야 한다. 어시스턴트가 다음에 무엇을 할지 정하는 데, 이 호출을 했다는 기록과 그 입력이 여전히 중요하다.
도구 호출
t7(Read, 4,213자)의 출력 전문이 이력에 원문 그대로 남아야 한다. 어시스턴트에게 그 내용이 아직 필요하고, 도구를 다시 실행하는 것으로는 대신할 수 없다.
두 확률을 keepThreshold(기본 0.5)와 견주어 세 가지 결과 중 하나로 정한다.
| 조건 | 결과 |
|---|---|
keepResult가 기준 이상 | 호출과 결과를 모두 그대로 둔다 |
keepResult는 미달이고 keepCall이 기준 이상 | 호출은 두고, 결과는 앞부분 truncateHeadChars자(기본 300자)와 한 줄 안내만 남긴다 |
| 둘 다 미달 | 호출과 결과를 함께 지운다 |
잘려 나간 뒷부분에는 [fast-jev-compaction truncated 3913 chars of this tool result; re-run the tool if needed] 같은 안내가 대신 들어간다. 원래 결과가 오류였다면 안내에 (error)가 붙는다.

옵션 기본값은 다음과 같다.
| 옵션 | 기본값 | 하는 일 |
|---|---|---|
apiKey | TYPESAFE_API_KEY | TypeSafe API 키 |
model | jev-latest | Jev 모델 이름 |
baseUrl | https://api.typesafe.ai/v1/systemone | System One 엔드포인트 |
goal | 마지막 사용자 프롬프트 3개 | 상태에 함께 넣는 현재 과제 설명 |
keepThreshold | 0.5 | 남기는 데 필요한 최소 확률 |
preserveRecentMessages | 6 | 손대지 않는 최근 메시지 수 |
maxStateTokens | 25000 | 상태의 추정 토큰 상한 |
maxRequestTokens | 30000 | 상태와 질문 한 묶음을 합친 상한 |
truncateHeadChars | 300 | 버리는 결과에서 남길 앞부분 길이 |
Claude Code 플러그인
hooks/fast-jev.ts는 얇은 어댑터다. 플러그인 옵션을 읽고 TypeSafe 키를 찾는다. 그 다음 session.compact 이벤트가 준 대화 기록을 라이브러리에 넘기고, 처리된 결과를 다시 세션 메시지로 되돌린다. 등록하는 훅은 두 개다.
session.compact는 실제 압축을 수행한다. 줄어든 비율이minReductionRatio(기본 0.25)에 못 미치거나 어딘가에서 예외가 나면next(event)로 내장 요약에 넘긴다.turn.complete는context.percent가compactAtPercent(기본 60)에 도달하면 압축을 요청한다. 중복 실행을 막는 가드가 하나 걸려 있다.

결과는 토스트 알림으로 보여 준다. 성공하면 kept 42/97 messages, no summary (…)처럼 뜬다. 전체 메시지 97개 가운데 42개를 남겼다는 표시다. 내장 요약으로 넘어간 경우에는 fallback to built-in summary (…)가 뜬다. 진단용으로는 호출마다 t3:Read:drop_result/call=0.71/result=0.12 형태의 줄을 남기는데, 호스트의 4,096자 한도에 맞춰 여러 줄로 쪼개 기록한다.
설치하려면 함수 훅을 먼저 켜야 한다. Claude Code 2.1.274 이상에서만 쓸 수 있는 얼리 액세스 기능이다.
{ "env": { "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1", "TYPESAFE_API_KEY": "<your key>" } }
claude plugin marketplace add tamaratran/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compaction
저장소 안에 들어 있는 types/claude-code.d.ts는 2.1.274에서 뽑아낸 선언 파일이고 크기가 42만 자를 넘는다. 저자는 Claude Code 버전을 올릴 때마다 이 파일을 다시 생성하고 검토하라고 적어 두었다.
macOS용 SwiftUI 데모 앱도 딸려 있다. API를 호출하지 않고 미리 짜 둔 대화로 압축 과정을 연출해 보여 주는 앱인데, 저자는 화면 녹화용으로 만들었다고 밝혔다.
저장소가 스스로 밝힌 한계
README의 「Limitations」 절은 네 가지를 적었다.
- 대상은 도구 호출과 도구 결과뿐이다. 텍스트 메시지는 출력에서 지워지지도 짧아지지도 않는다. Jev가 보는 상태 안에서만 줄어든다.
- 토큰 크기는 토크나이저를 거치지 않고 문자수에서 뽑아낸 추정치다.
- 확률 보정은 요청 하나 안에서만 맞춰 두었다. 확률은 어떤 결과를 지워도 안전하다는 증명이 아니다. 대신 어시스턴트는 언제든 도구를 다시 실행할 수 있다.
- 상태 전문을 요청마다 반복해서 보내므로, 이력이 상태 상한에 가까울수록 질문 몇 개마다 요청을 하나씩 새로 보내게 된다.
Jev는 이미 줄여 놓은 사본을 보고 판정한다
원문 보존이라는 약속을 어디까지 적용하는지 따져 보면 비대칭이 하나 나오는데, 저자도 이것을 숨기지 않았다. 원문 보존은 컴팩션 결과물에만 해당하는 약속이고, 판정에 들어가는 입력은 그 약속 밖에 있다. Jev에게 보내는 상태는 25,000토큰에 맞추느라 긴 텍스트를 앞부분과 끝부분만 남기고 줄이고, 오래된 메시지를 한 줄 메모로 바꾸고, 도구 호출을 한 줄로 압축한다. 무엇을 영구히 지울지 결정하는 순간에 Jev는 이미 한 번 줄여 놓은 사본을 읽고 있다. 저자는 이 사정을 감추는 대신 축소가 어느 단계까지 갔는지를 stats.stateStage에 기록하도록 만들어 두었다.

저자는 그 비대칭을 상쇄하려고 장치를 두 개 뒀다. 하나는 상태에 늘 함께 들어가는 안내문에서 “어시스턴트는 언제든 도구를 다시 실행하거나 파일을 다시 읽을 수 있다"라고 알려 주는 문장이다. 이 한 줄이 Jev에게 삭제의 대가를 낮게 잡아도 된다고 미리 알려 준다. 다른 하나는 세 갈래 판정의 가운데 칸이다. 호출은 남길 만하지만 결과는 아니라고 판정되면 결과의 앞 300자가 남는다. 판정이 틀렸더라도 본문은 잃을지언정 무슨 도구를 왜 불렀는지는 알 수 있다.
비용은 이 설계를 채택할 때 큰 부담이 되지 않는다. 나는 얼마 전 atom 카드 선별 실험에서 같은 엔드포인트를 직접 호출해 봤다. Jev는 입력 100만 토큰당 0.042달러를 받고 출력은 무료였다. 한 요청에 질문 195개를 넣어도 답은 1초에서 2초 사이에 돌아왔다. 25,000토큰짜리 상태 하나는 0.001달러 남짓이다. 컴팩션 한 번에 요청을 서너 개 쓴다 해도 1센트에 미치지 못한다. 그러니 이 플러그인을 쓸지 말지를 요금이 결정하지는 못한다. 판정이 얼마나 정확한지, 그리고 압축 때마다 몇 초씩 더 기다릴 수 있는지가 변수다.
플러그인 기본값 가운데 compactAtPercent는 60으로 잡혀 있다. 컨텍스트가 절반을 조금 넘겼을 뿐인데 벌써 압축을 요청한다. 요약을 만들지 않으니 압축 한 번이 대화의 성격을 바꾸지 않고, 그래서 자주 돌려도 괜찮다는 판단이 이 기본값에 담겨 있다. 요약 기반 컴팩션에서는 택하기 어려운 숫자다.
출처
tamaratran, fast-jev-compaction, 2026년 9월 17일 공개, MIT 라이선스.
원문: https://github.com/tamaratran/fast-jev-compaction
본문 삽화는 원문에 인용할 만한 이미지가 없어 치비 서소영 라인아트로 대신했다.3
README는
npm install fast-jev-compaction으로 설치하라고 안내하지만, 2026년 9월 21일 아침에 npm 레지스트리를 조회해 보니 이 이름의 패키지는 아직 올라와 있지 않았다(404). 당분간은 저장소를 직접 받아서 써야 한다. Claude Code 플러그인 쪽은 저장소의.claude-plugin/marketplace.json이 곧 마켓플레이스라서 별도 배포 절차가 필요 없다. ↩︎GitHub REST API의 저장소 메타데이터를 2026년 9월 21일 아침에 조회한 값이다. ↩︎
블로그 글 「느낌적인 느낌을 숫자로 옮기는 일」의 치비 서소영 라인아트를 참조하여 gpt-image-2.5-flare image-to-image로 생성했다. ↩︎
