- 뭘 해결하나: 지금 대화가 얼마나 찼는지 몰라 한계를 갑자기 만나는 문제. 화면 맨 아래 한 줄로 잔량이 보이면 끊을 타이밍을 미리 압니다
- 내가 한 일:
statusline 달아줘두 마디. 스크립트를 짜고 설정에 등록한 건 에이전트입니다 - 배운 것: 그 에이전트가 두 번 틀렸습니다. 한 번은 스스로 잡았고, 한 번은 제가 화면을 보여줘서 잡혔습니다
🎁 이 글 맨 끝에 클로드코드 사용 역량 평가를 위한 「7축 진단 프롬프트」 전문을 통째로 뒀습니다. 지난 편의 6축 채점에 프롬프트 품질 축을 더해 7축으로 확장한 것입니다. 읽는 건 나중에 하시고, 지금 스크롤을 내려 복사해서 여러분 환경부터 돌려 보세요.

이런 문제 겪고 있다면
클로드코드로 한창 작업하다 대화가 다 찼다는 걸 갑자기 알게 된 적 있으신가요. 그게 올 줄은 전혀 모르고 있었다는 게 문제입니다. 미리 알았으면 적당한 데서 끊고 새 창에서 시작했을 텐데요.
창을 여러 개 띄우면 하나 더 붙습니다. 창을 바꿨는데 여기가 어느 프로젝트인지 순간 헷갈리고, 브랜치를 확인하려 git branch를 또 칩니다. 저는 수학 과외에 쓸 도구들을 AI와 붙이고 있는데, 프로젝트가 넷으로 늘면서 이게 매일 겪는 일이 됐습니다.
지난 편에서 AI에게 제 사용 습관을 채점시켰더니 「상태 가시성」이 10점 만점에 2점이었습니다. 이번 편은 그 2점을 실제로 고치는 이야기입니다.
AI가 한 대화에서 기억하고 있는 분량입니다. 담을 수 있는 양에 상한이 있어서, 꽉 차면 앞부분을 요약해 압축하거나 새 대화를 시작해야 합니다. 압축이 돌면 “그때 왜 그렇게 결정했는지”가 사라지므로, 그 전에 끊는 게 좋습니다.
시킨 건 두 마디였습니다
제가 입력한 건 이게 전부입니다.
statusline 달아줘
여기서 미리 말씀드릴 게 있습니다. 아래 나오는 스크립트를 제가 짠 게 아닙니다. 저는 정규식도 파일 다루는 코드도 못 씁니다. 제가 한 일은 “이게 필요하다”고 말한 것, 그리고 나온 결과가 맞는지 판단한 것뿐입니다.
에이전트가 시키지도 않았는데 알아서 한 일이 꽤 됩니다.
| 알아서 한 일 | 왜 그게 좋은 판단이었나 |
|---|---|
| 프로젝트별이 아니라 전역 설정에 등록 | 프로젝트마다 다시 달 필요가 없다 |
| 손대기 전에 설정 파일 백업 | 되돌릴 자리를 먼저 만들어 뒀다 |
| 등록 후 원본과 대조 | 기존 훅 설정이 날아가지 않았음을 확인 |
| “다른 프로젝트에서도 되냐”고 묻자 말로 답하지 않고 다섯 곳에서 실행 | git 저장소가 아닌 폴더에서도 안 깨지는지 확인 |
되돌릴 자리를 먼저 만들고 손대는 것. 제가 혼자 했으면 안 했을 순서입니다.
한 줄이 말해주는 다섯 가지
결과가 이렇습니다. 왼쪽부터 프로젝트명 · 세션 구분자 · 브랜치 · 모델 · 컨텍스트 게이지입니다.
log-to-contents·1ae55 ⎇ main Opus 5 (1M context) ▓▓▓▓▓▓░░░░ 62%
아래는 다른 프로젝트 창에서 찍은 실물입니다. 프로젝트 이름과 잔량만 다를 뿐 구조는 같습니다.

제 원래 고민이 이 다섯 조각에 하나씩 대응합니다.
| 알고 싶던 것 | 전 | 후 |
|---|---|---|
| 지금 어느 프로젝트인가 | 창 제목을 보거나 짐작 | 상시 표시 |
| 같은 프로젝트 창 두 개 구분 | 불가능 | 세션 구분자 5글자 |
| 어느 브랜치인가 | git branch 를 침 | 상시 표시 |
| 어느 모델로 돌고 있나 | 짐작 | 상시 표시 |
| 컨텍스트가 얼마나 찼나 | 알 방법이 없었음 | 게이지 + 75%부터 경고 |
마지막 줄이 이 글의 제목입니다. 컨텍스트는 다 차야 알던 것이었는데, 이제 반쯤 찼을 때 보입니다. 게이지는 50%부터 노랑, 75%부터 빨강으로 바뀌고 빨강에는 /clear 안내가 붙습니다. 그게 「새 창에서 시작할 타이밍」입니다.

에이전트가 두 번 틀렸습니다
여기가 진짜 배운 부분입니다. 시켜서 받은 결과물이 처음부터 맞지는 않았습니다.
첫 번째 — 스스로 잡았습니다
설정에 등록하기 전에 에이전트가 스스로 한 번 돌려 봤는데, 프로젝트명 자리에 경로가 통째로 찍히고 게이지는 아예 안 나왔습니다. 에러는 한 줄도 없었고요.
에이전트가 저장한 파일을 다시 열어 대조하더니 원인을 찾았습니다. 셸로 여러 줄을 한 번에 쏟아붓는 방식(heredoc)을 썼는데, 그 과정에서 백슬래시가 반으로 줄어든 채로 저장됐던 겁니다.
| 원래 코드 | 저장된 결과 | 증상 |
|---|---|---|
/[\\/]/ | /[\/]/ | 윈도우 경로를 못 나눠 경로가 통째로 찍힘 |
'(\\d+)' | '(\d+)' | 숫자 대신 글자 d를 찾게 돼 게이지가 항상 0 |
고친 방법이 인상적이었습니다. 문법을 더 파고들어 셸을 길들이는 대신, 에이전트는 그 방식을 아예 버리고 파일 쓰기 도구로 다시 썼습니다. 저는 이 대목에서 배운 게 있어요. 도구가 조용히 값을 바꿔놓는 자리를 만나면, 그 도구를 이기려 들기보다 다른 길로 가는 게 빠르다는 겁니다.

두 번째 — 제가 화면을 보여줘서 잡혔습니다
한참 뒤에 다른 프로젝트에서도 잘 나오는지 확인하려고 캡처를 찍어 보냈습니다. 게이지가 34%를 가리키고 있었고, 저는 그럴듯해서 넘어갔죠.
그런데 에이전트가 그 화면을 보더니 자기 결함을 실토했습니다. 헤더에 Opus 5 (1M context)라고 적혀 있는데 스크립트는 분모를 20만으로 고정해 뒀다는 겁니다. 실제 창은 100만인데요.
| 분모 | 같은 토큰 수(138,313개)의 표시 |
|---|---|
| 200,000 (스크립트 고정값) | 69% |
| 1,000,000 (실제 창 크기) | 14% |
계산은 정확했고 분자도 진짜였습니다. 분모만 다섯 배 작았습니다. 저는 34%면 아직 여유라고 보고 넘겼는데, 실제로는 7% 언저리였던 거죠. 지금은 모델 이름에 적힌 (1M context)를 읽어 분모로 쓰도록 에이전트가 고쳐 놨습니다.

뼈아픈 건 이겁니다. 에이전트는 설치를 끝내고 「알아둘 한계」로 분모가 20만 고정이라고 이미 적어 줬습니다. 제가 안 읽었을 뿐입니다.
남이 만들어준 걸 검수하는 세 가지
코드를 못 읽어도 할 수 있는 것들입니다. 저는 세 번째를 안 해서, 다섯 배 부풀려진 숫자를 그대로 믿고 있었습니다.
- 「알아둘 한계」를 끝까지 읽습니다. 잘 만드는 에이전트는 자기 결함을 먼저 신고합니다. 설치가 끝났다는 말 다음이 제일 안 읽히는 자리인데, 거기 답이 있었습니다.
- 되돌릴 자리가 있는지 묻습니다. “설정 파일 백업했어?” 한마디면 됩니다. 이번엔 알아서 했지만 매번 그러진 않습니다.
- 첫날은 숫자를 의심합니다. 모델 이름 옆 괄호를 보세요.
(1M context)라고 적혀 있는데 게이지가 유독 높으면, 분모가 20만으로 박혀 있는 겁니다. 저는 그 둘을 나란히 놓지 않아서 못 잡았습니다.
그래서 뭘 하면 되나
- 클로드코드에
statusline 달아줘라고 합니다. 어떤 항목을 보고 싶은지 덧붙이면 더 좋습니다(“프로젝트·브랜치·컨텍스트 잔량”). - 되돌릴 자리를 확인합니다. 설정 파일을 백업했는지, 기존 설정이 보존됐는지 물어봅니다.
- 첫날 게이지를 한 번 검산합니다. 쓰는 모델의 창 크기와 표시된 비율이 말이 되는지 봅니다.
- 직접 파일을 두고 싶다면 부록 A의 전문을
~/.claude/statusline.js로 저장하면 됩니다.
FAQ
Q. 코딩을 못해도 되나요?
네. 저도 못 씁니다. 필요한 건 “뭐가 안 보여서 불편하다”를 말하는 것과, 나온 결과를 의심해 보는 것뿐입니다.
Q. 맥이나 리눅스에서도 되나요?
아마 될 겁니다. 다만 제가 확인한 건 윈도우뿐입니다. 경로만 본인 것으로 바꾸면 되는 구조입니다.
Q. 게이지 숫자가 실제와 다르면요?
분모부터 의심하세요. 모델 표시명에 (1M context) 같은 표기가 없으면 20만으로 떨어집니다. 그 기본값을 본인 창 크기로 바꿔 달라고 하면 됩니다.
Q. 상태줄 때문에 느려지지 않나요?
체감은 없습니다. 30MB짜리 기록에서도 파일 끝 300KB만 읽도록 만들어져 있어서, 기록이 더 커져도 읽는 양은 그대로입니다.
부록 A — 에이전트가 내놓은 스크립트 전문
에이전트가 만들어 준 결과물이고, 두 번의 수정이 반영된 최종본입니다. ~/.claude/statusline.js로 저장한 뒤 ~/.claude/settings.json에 아래 설정을 더하면 됩니다. 그대로 가져다 쓰셔도 됩니다.
{
"statusLine": {
"type": "command",
"command": "node \"C:/Users/<이름>/.claude/statusline.js\"",
"padding": 0
}
}
// Claude Code statusline: 어느 세션 · 어느 브랜치 · 컨텍스트 얼마나 찼나.
// 상태줄이 작업을 막으면 안 되므로, 무엇이 잘못돼도 조용히 한 줄만 찍고 끝낸다.
const fs = require('fs');
const { execSync } = require('child_process');
const C = { b: '\x1b[1m', dim: '\x1b[2m', cyan: '\x1b[36m', mag: '\x1b[35m',
grn: '\x1b[32m', yel: '\x1b[33m', red: '\x1b[31m', r: '\x1b[0m' };
const SPLIT = /[\\/]/;
// 창 크기는 모델 표시명이 알려준다 — "Opus 5 (1M context)". 못 읽으면 200k.
function windowSize(name) {
const m = (name || '').match(/(\d+(?:\.\d+)?)\s*([MK])\s*context/i);
if (!m) return 200000;
return Math.round(Number(m[1]) * (m[2].toUpperCase() === 'M' ? 1e6 : 1e3));
}
// 트랜스크립트 꼬리만 읽는다 — 30MB 파일을 매 렌더마다 통째로 읽지 않기 위해.
function contextTokens(p) {
const fd = fs.openSync(p, 'r');
try {
const size = fs.fstatSync(fd).size;
const len = Math.min(size, 300000);
const buf = Buffer.alloc(len);
fs.readSync(fd, buf, 0, len, size - len);
const found = buf.toString('utf8').match(/"usage":\{[^}]*\}/g);
if (!found) return 0;
const last = found[found.length - 1];
const n = (k) => {
const m = last.match(new RegExp('"' + k + '":(\\d+)'));
return m ? Number(m[1]) : 0;
};
return n('input_tokens') + n('cache_creation_input_tokens') + n('cache_read_input_tokens');
} finally {
fs.closeSync(fd);
}
}
// -b 로 브랜치, -uno 로 untracked 무시(대형 레포에서 빠르게).
function git(cwd) {
const out = execSync('git status --porcelain=v1 -b -uno', {
cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 1500,
});
const lines = out.split('\n');
const br = (lines[0].match(/^## ([^.\s]+)/) || [, '?'])[1];
return br + (lines.slice(1).some(Boolean) ? '*' : '');
}
let d = {};
try { d = JSON.parse(fs.readFileSync(0, 'utf8')); } catch {}
const cwd = (d.workspace && d.workspace.current_dir) || d.cwd || process.cwd();
const proj = cwd.replace(/[\\/]+$/, '').split(SPLIT).pop() || '?';
const tag = (d.session_id || '').slice(0, 5);
const model = (d.model && d.model.display_name) || '';
let branch = '';
try { branch = git(cwd); } catch {}
let pct = null;
try {
if (d.transcript_path && fs.existsSync(d.transcript_path)) {
pct = Math.min(99, Math.round(contextTokens(d.transcript_path) / windowSize(model) * 100));
}
} catch {}
const parts = [];
parts.push(C.b + C.cyan + proj + C.r + (tag ? C.dim + '·' + tag + C.r : ''));
if (branch) parts.push(C.mag + '⎇ ' + branch + C.r);
if (model) parts.push(C.dim + model + C.r);
if (pct !== null) {
const col = pct >= 75 ? C.red : pct >= 50 ? C.yel : C.grn;
const fill = Math.round(pct / 10);
parts.push(col + '▓'.repeat(fill) + C.dim + '░'.repeat(10 - fill) + C.r +
col + ' ' + pct + '%' + C.r + (pct >= 75 ? ' ' + C.red + '/clear' + C.r : ''));
}
process.stdout.write(parts.join(' '));
부록 B — 7축 진단 발주서 전문
지난 편의 6축 채점을 프롬프트 품질까지 넣어 7축으로 확장한 발주서입니다. 통째로 복사해서 여러분의 클로드코드에 그대로 붙이면 됩니다.
# 발주: 전 프로젝트 Claude Code 사용 역량 감사 (7축)
## 목적
"클로드코드를 잘 쓰고 있는가"를 프로젝트 한 곳이 아니라 전 프로젝트 실측으로 판정한다.
아부·완곡어법 금지. 근거 없는 칭찬 금지. 각 판정은 파일 경로나 수치를 달고 나온다.
## 측정 대상
~/.claude/projects/ 아래 전 프로젝트 트랜스크립트(.jsonl),
각 프로젝트의 .claude/settings*.json / CLAUDE.md / skills / agents / hooks,
~/.claude/settings.json (전역).
## 7축과 측정 방법 (반드시 수치로)
1. 반복의 자산화 — 스킬·훅·커맨드·에이전트 수, CLAUDE.md 존재/길이.
같은 절차를 자연어로 재설명한 흔적이 몇 번인지 세라.
2. 검증 루프 — 완료 판정이 테스트/명령 종료코드인가, 사람 눈인가.
"확인해봐/맞아?/잘 됐나" 류 확인 요청 프롬프트 비율.
3. 위임의 폭 — subagent·background task·worktree 실사용 횟수 vs
사람이 여러 세션을 손으로 병렬 운용한 정황(동시간대 세션 겹침).
4. 컨텍스트 위생 — 프로젝트별 세션 수 / 세션당 평균 MB / 컴팩션 횟수.
🔴 컴팩션은 반드시 온전한 패턴으로 셀 것:
grep -c '"subtype":"compact_boundary"' <transcript.jsonl>
짧은 형태(compact_boundary)는 그 단어를 언급만 해도 세어져 값이 부풀려진다.
기준: 컴팩션 1회 이상이면 그 지점이 원래 /clear 했어야 할 자리다.
5. 마찰 제거 — allowlist 규칙 중 (a)전역 allow가 비어 있어 프로젝트마다 되풀이 승인하는 항목
(`Bash(git add:*)`와 `Bash(git add *)`는 공식 문서상 둘 다 유효하다 — 문법을 원인으로 삼지 말 것)
(b)일회성 명령 전문이 박힌 쓰레기 항목. 각각 파일:항목으로 열거.
6. 상태 가시성 — statusline·output style 설정 여부, HANDOVER/WORKLOG 최신성,
"지금 어디까지 했지" 류 프롬프트 빈도.
7. 프롬프트 퀄리티 (가장 비중 크게)
전 프로젝트 user 메시지를 뽑아 아래를 실측하라.
추출 예: jq -r 'select(.type=="user") | .message.content' *.jsonl
⚠️ user 타입에는 도구 실행 결과도 섞인다. tool_result 를 걸러야 사람 프롬프트만 남는다.
7-1 정정률 — 직전 응답을 되돌리는 프롬프트 비율
("아니 그게 아니라", "다시", "취소", "원래대로", "왜 그걸 했어")
7-2 성공기준 동봉률 — 검증 가능한 완료조건이 있는 비율
7-3 증거 동봉률 — 파일경로·에러 원문·재현 절차를 준 비율 vs 무증거 신고 비율
7-4 배치성 — 독립 요청을 한 메시지에 묶은 비율 vs 한 줄씩 쪼갠 비율
7-5 되묻기 유발률 — Claude가 질문으로 되받은 비율
7-6 길이 분포 — 20자 미만 단문 비율, 그 단문 뒤 정정률
7-7 스킬 활용 — /스킬 호출 vs 같은 일을 자연어로 다시 설명한 비율
각 지표에 대해 실제 프롬프트 3개를 원문 인용하고,
같은 의도의 개선판을 옆에 나란히 써라(before/after).
추상적 조언 금지 — 그대로 복붙할 수 있는 문장이어야 한다.
## 출력 형식
1. 7축 점수표(10점 만점) + 프로젝트별 편차 — 어느 프로젝트가 최악인지 명시
2. 전 프로젝트 공통 문제 / 특정 프로젝트 국한 문제를 분리
3. 프롬프트 before/after 최소 10쌍
4. 처방을 효과 순으로 5개, 각각 소요시간과 실행 명령까지
5. 마지막에 아부 없는 한 문단 총평
## 금지
- 측정 안 한 축을 추정으로 채우지 말 것. 못 쟀으면 "미측정"이라 쓸 것.
- 점수는 주관 채점이다. 실측치와 섞어 제시하지 말 것.
- 프롬프트 원문 인용 시 비밀·개인정보는 마스킹.
- 트랜스크립트는 크다. 전문 로딩 말고 jq/grep 집계로 처리할 것.
돌려 보시면 아마 저처럼 낮은 점수가 나올 겁니다. 저는 지난 편에서 6축으로 채점받아 60점 만점에 29점이었습니다. 결과가 나오면 한 번은 되물어 보세요 — 「이 판정의 근거가 뭐냐」고요. 이 글의 상태줄도 한 번은 에이전트가 스스로, 한 번은 제가 화면을 내밀어서 제자리를 찾았습니다.