안녕하세요 여러분, 터미널 내 Claude Code를 위한 작은 커스텀 상태 표시줄(statusline)을 제작하여 이곳에 공유하고자 합니다. 거창한 것은 아니며, 제 개인적인 워크플로우를 위해 만든 것이지만 다른 분들에게도 유용하거나 시도해 볼 만한 재미있는 요소가 될 것 같아 가져왔습니다. 이 상태 표시줄은 사용자 이름, 프로젝트/디렉토리, 현재 git 브랜치, 활성화된 모델 및 해당 모델의 사고 수준(thinking level), 권한 우회(bypass permissions) 활성화 여부, 그리고 현재 실행 중인 서브 에이전트(sub-agents)의 수를 보여줍니다. 그 아래에는 세 개의 바(bar)가 있습니다: 컨텍스트 사용량(context usage), 5시간 사용 제한, 그리고 7일 사용 제한(초기화 날짜 포함)입니다. 또한 토큰 사용량과 현재 작업이 표시된 서브 에이전트의 실시간 목록도 제공합니다. 획기적인 것은 아니지만, 별도의 명령어를 실행할 필요 없이 모든 것을 한눈에 파악할 수 있는 방법입니다. 혹시 본인의 설정에 맞춰 수정하고 싶은 분들을 위해 제가 사용한 프롬프트/설정(config)을 아래에 게시합니다. 피드백이나 개선을 위한 아이디어가 있다면 기쁘게 듣겠습니다. https://preview.redd.it/wkkhsurci5hh1.png?width=1940&format=png&auto=webp&s=b70479bdc0b9590ae9ad8731ba596065939a5675 # Claude Code 상태 표시줄 + 에이전트 디스플레이 — 복제 가이드 작동 중인 macOS 머신에서 Claude Code 입력창 아래에 렌더링되는 모든 요소와, 이를 다른 컴퓨터에서 바이트 단위로 동일하게 재현하는 방법입니다. 2026-08-03 기준 작동 중인 머신에서 캡처되었으며, Claude Code 버전은 v2.1.220 입니다. > 이 파일을 프롬프트로 사용하기. 이 파일 전체를 새 머신으로 복사하거나(또는 해당 리포지토리를 클론한 후) 다음 내용을 Claude Code에 붙여넣으세요: > > > 리포지토리 루트에 있는 statusline.md를 읽고, 내 Claude Code 상태 표시줄, 서브 에이전트 상태 표시줄, 그리고 커스텀 테마를 설명된 내용과 정확히 일치하게 설정해 줘. 주어진 내용과 정확히 일치하는 파일들을 생성하고, 기존에 내가 가지고 있는 키들을 누락시키지 않으면서 settings.json의 키들을 나의 기존 ~/.claude/settings.json에 병합해 줘. 그런 다음 마지막에 있는 검증 명령어를 실행하고 렌더링된 출력을 보여줘. > > > 에이전트가 필요로 하는 모든 것은 이 파일에 들어 있습니다 — 다른 머신에 접속할 필요가 없습니다. --- ## 1.
외형
입력창 아래에 두 줄이 위치하며, 각 줄은 전체 너비의 어두운 띠(bg 235)로 그려집니다. 띠의 왼쪽 가장자리에는 세 개의 게이지 중 가장 상태가 좋지 않은 색상을 띤 유색 왼쪽 가장자리 글리프(▌)가 표시됩니다:
▌ youruser | PMS | main | Opus 5 [high] | BYPASS 2 AGENTS
▌ ━━╸──── 41% | ━╸───── 32% (3h12m left) | ─────── 18% (resets Mon Aug 10)
(구분선은 박스 그리기 글리프가 아닌, 어두운 회색의 일반 | 기호입니다.)
1행 — identity (식별 정보): OS 사용자 이름 (cyan) · 프로젝트 폴더 (blue) · git 브랜치 (green) · 노력 수준(effort level)이 포함된 모델 이름 (white) · 배지(badges).
2행 — gauges (게이지): 항상 다음 순서를 따르며, 각 게이지는 7칸의 굵은 선 바(heavy-line bar)와 퍼센트(%)로 구성됩니다:
| 게이지 | 노란색 전환 | 빨간색 전환 | 접미사 (Suffix) |
|---|
| context | 20% | 30% | — |
| 5h limit | 50% | 80% | (3h12m left) — 리셋까지 남은 시간 |
| 7d limit | 50% | 80% | (resets Mon Aug 10) — 리셋 날짜 |
컨텍스트(context) 임계값은 의도적으로 공격적(20/30)으로 설정되었습니다. 이는 "거의 가득 찼음"을 알리는 신호가 아니라, 압축(compaction)이 곧 진행될 것임을 알리는 **조기 경보 (early warning)**입니다. 속도 제한(rate-limit) 임계값은 관례적인 50/80을 따릅니다.
Badges (배지): 1행에 유색 칩 형태로 렌더링되며, 해당되는 경우에만 표시됩니다:
BYPASS / AUTO-EDIT / PLAN — 권한 모드 (permission mode)
FAST — 빠른 모드 (fast mode) 활성화
N AGENTS — 실행 중인 서브에이전트(subagent) 수 (§4의 서브에이전트 상태 표시줄 참조)
agent:<name>, style:<name>, vim 모드, PR #123 (리뷰 상태에 따라 색상 지정)
Agent panel rows (에이전트 패널 행). 에이전트 패널의 각 서브에이전트는 상태 색상이 입혀진 가장자리를 가진 일치하는 띠를 가집니다:
▌ Explore · ━╸───── 28% · 14.2k tok · 1m3s · [high] · search for the relay handler
가장자리 색상: 빨간색 = 실패/취소(failed/cancelled), 초록색 = 완료(completed), 노란색 = 대기/큐(pending/queued), 흰색 = 실행 중(running). 여유 공간을 위해 마지막 에이전트 행 뒤에는 빈 줄이 추가됩니다.
2.
생성할 파일: ~/.claude/ 아래에 세 개의 파일을 생성합니다: | 파일 | 용도 | | ------------------------- | ------------------------------------------------------------- | | statusline.js | 입력창 아래의 두 줄 상태 표시줄 (status line) | | subagent-statusline.js | 에이전트 패널 내 에이전트별 행 본문 + 에이전트 수 피드 | | themes/pms.json | 호박색(amber) 액센트가 적용된 커스텀 다크 테마 | 모든 파일은 의존성 없는 Node (child_process, fs, os, path만 사용) 환경에서 작동하며, jq나 npm install이 필요하지 않습니다. PATH에 Node ≥ 18 버전이 설정되어 있어야 합니다. > 소스 머신에는 jq 기반의 bash 버전인 레거시 ~/.claude/statusline-command.sh가 존재합니다. 이는 settings.json에서 참조되지 않는 대체된(superseded) 파일이므로, 이를 포팅하지 마세요. ---
3. ~/.claude/statusline.js
이 파일을 정확히 생성하세요:
#!/usr/bin/env node
'use strict';
const { execSync } = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
function safe(fn, fallback) {
try {
const v = fn();
return v === undefined || v === null ? fallback : v;
} catch (e) {
return fallback;
}
}
let raw = '';
try {
raw = fs.readFileSync(0, 'utf8');
} catch (e) {
raw = '';
}
let input = {};
try {
input = raw ?
JSON.parse(raw) : {}; } catch (e) { input = {}; } const RESET = '\x1b[0m'; const DIM = '\x1b[2m'; const CYAN = '\x1b[36m'; const WHITE = '\x1b[37m'; const BLUE = '\x1b[34m'; const GREEN = '\x1b[32m'; const YELLOW = '\x1b[33m'; const RED = '\x1b[31m';
path.basename(cwd) : '';
function getPermissionMode(sessionId) { const cacheFile = path.join(os.tmpdir(), `statusline-permmode-${sessionId || 'nosession'}`); try { return fs.readFileSync(cacheFile, 'utf8'); } catch (e) { } let mode = ''; let read = false; try { const out = execSync('ps -axo pid=,ppid=,args=', { stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 8 * 1024 * 1024, }).toString(); read = true; const procs = new Map(); out.split('\n').forEach((line) => { const m = line.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/); if (m) procs.set(Number(m[1]), { ppid: Number(m[2]), args: m[3] }); }); let pid = process.ppid; for (let i = 0; i < 10 && pid && procs.has(pid); i += 1) { const proc = procs.get(pid); if (/--dangerously-skip-permissions/.test(proc.args)) { mode = 'bypassPermissions'; break; } const m = proc.args.match(/--permission-mode[= ]+(\S+)/); if (m) { mode = m[1]; break; } pid = proc.ppid; } } catch (e) { mode = ''; }
function barState(pct, yellowAt, redAt) { if (pct === null || pct === undefined || pct === '') return null; const p = Math.round(Number(pct)); if (Number.isNaN(p)) return null; if (p >= redAt) return 2; if (p >= yellowAt) return 1; return 0; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43