---
ai_assisted: true
title: "디스크 유틸 — zsh alias와 Claude Skill 두 인터페이스"
description: "디스크 셸 함수를 zsh alias(dh, dgh, dol)와 Claude Skill로 노출하고 stale-while-revalidate 캐시를 붙인 구성"
pubDate: 2026-05-20
category: "Development"
tags: ["zsh", "Claude Code", "Skill", "Dotfiles", "Disk Management", "stale-while-revalidate", "Dev Workflow"]
heroImage: ""
serial: 19
draft: false
published: true
---

디스크 사용량 조회·정리 로직을 zsh alias(`dh`/`dgh`/`dol` 등)와 Claude Skill 두 인터페이스로 동시에 노출하는 셋업입니다. 같은 셸 함수가 터미널에서는 짧은 alias로, 에이전트 안에서는 자연어 호출로 사용됩니다. 이 글에서는 인터페이스 분리 원칙, 두 표현의 차이, 코드 공유 구조, 그리고 stale-while-revalidate 적용을 정리합니다.


## 두 인터페이스가 같은 로직을 공유한다

`disk_utils.zsh`는 `~/.oh-my-zsh/custom/`에 위치하는 472줄짜리 zsh 스크립트입니다. `dh`를 치면 `disk_home()` 함수가 실행되고, "디스크 어디가 문제야"라고 Claude Code에 물으면 `disk-manager` Skill이 같은 함수 집합을 가리키며 분석을 시작합니다.

두 인터페이스는 표면만 다를 뿐 동일한 함수를 호출합니다. 사람은 alias로 직접 실행하고, 에이전트는 SKILL.md에 기술된 마인드모델과 명령어 목록을 참고해 자연어 지시를 구체적인 셸 명령으로 번역합니다. 로직은 한 곳에만 존재하고, 두 방향으로 노출되는 구조입니다.

이 구조의 실질적 이점은 중복 제거입니다. 디스크 분석 방법론을 에이전트용 SKILL.md에 한 번만 기록해두면, "어디가 제일 크냐"는 자연어 질문도, 터미널에서 직접 치는 `disks`도 동일한 탐색 순서를 따릅니다.


## zsh 측 인터페이스

`disk_utils.zsh`의 alias 목록은 다음과 같습니다.

```zsh
alias disks='disk_report'    # 전체 대시보드 (숫자 선택 메뉴)
alias dh='disk_home'         # 홈 디렉토리 주요 항목 (상위 15개)
alias dgh='disk_github'      # GitHub 프로젝트별 크기
alias dicl='disk_icloud'     # iCloud Drive
alias dcol='disk_colima'     # Colima VM — Docker 이미지 + 프로젝트 참조
alias dol='disk_ollama'      # Ollama 모델 목록 + 용량
alias das='disk_appsupport'  # Library > Application Support
alias dlc='disk_libcache'    # Library > Caches
alias dct='disk_cache_tools' # ~/.cache (CLI·개발 도구)
alias ddt='disk_dev_tools'   # npm/Bun/nvm/pyenv/Cursor/Gradle/GHCup
alias dml='disk_ml_cache'    # HuggingFace/uv/PyTorch/Keras/TensorFlow/pip
alias dcache='disk_clean_cache'
alias dnpm='disk_clean_npm'
alias dref='disk_refresh'
alias ddiff='disk_diff'      # 변동 현황 (기본 24h)
alias dhist='disk_hist'      # 용량 추이 차트
alias dsnap='disk_snap'      # 즉시 스냅샷 촬영
```

`disks`는 대화형 대시보드입니다. 실행하면 전체 현황과 홈 디렉토리 요약을 보여준 뒤 숫자 메뉴로 진입합니다. `1`은 GitHub 프로젝트, `3`은 Colima VM, `d`는 24시간 변동 현황, `h`는 카테고리별 추이 차트입니다.

조회 함수 대부분은 `_get_or_update_cache()`를 경유합니다. 결과를 `~/.disk_cache/` 아래 파일에 캐시하고, TTL(6시간) 이내에는 파일을 그대로 읽어 반환합니다. 이 패턴에 대해서는 아래에서 따로 다룹니다.

`ddiff`와 `dhist`는 SQLite 기반의 이력 조회입니다. `dsnap`으로 스냅샷을 찍으면 `~/.disk_cache/disk_history.db`에 카테고리별 용량이 기록되고, 이후 `ddiff 48`(48시간 전 대비)이나 `dhist colima 30`(30일간 Colima VM 추이)으로 변화를 추적할 수 있습니다. launchd plist(`com.jaesolshin.disk-index.plist`)가 6시간마다 자동으로 `refresh.sh`를 실행해 스냅샷을 누적합니다.

`dcol`은 Colima 실행 여부에 따라 출력이 달라집니다. Colima가 중지 상태면 GitHub 프로젝트의 `docker-compose*.yml`에서 `image:` 라인을 긁어 어떤 이미지가 정의돼 있는지 보여줍니다. 실행 중이면 `docker system df`와 이미지별 프로젝트 참조를 함께 출력합니다.


## Claude Skill 측 인터페이스

`disk-manager` Skill의 description은 다음과 같습니다.

> 디스크 사용량을 모니터링하고 정리합니다. 대용량 파일 찾기, 폴더별 크기 분석, 캐시 정리, ML 프레임워크 모니터링, Docker 이미지 분석 등에 사용합니다. dust/fd 기반 고속 스캔, stale-while-revalidate 캐싱, launchd 주기적 인덱싱.

Claude Code는 이 description을 보고 디스크 관련 자연어 요청을 이 Skill로 라우팅합니다. 트리거 표현으로는 "디스크가 가득 찼어", "HuggingFace 캐시가 얼마나 돼", "어떤 프로젝트가 제일 크냐" 같은 형태가 해당됩니다.

SKILL.md는 Claude가 따를 탐색 순서를 명시합니다.

```
1. 전체 현황 파악
   df -h | grep /System/Volumes/Data

2. 홈 디렉토리 1단계 드릴다운
   du -sh ~/Documents ~/Library ~/Downloads ~/Movies ~/.cache ~/.ollama ~/.colima

3. Library 드릴다운
   dust -d 1 -n 15 ~/Library

4. Library/Containers 드릴다운 (함정 구간)
   dust -d 1 ~/Library/Containers

5. Colima VM 실제 사용량 확인
   du -sh ~/.colima/

6. Docker 이미지 분석
   docker images + pull 시점 확인

7. 캐시 분석
   ~/.cache, ~/Library/Caches 항목별 크기
```

에이전트는 이 순서를 건너뛰지 않도록 안내받습니다. 단계를 임의로 생략하면 "Library/Containers에 Docker Desktop VM이 50GB 이상 잡혀 있는데 눈에 안 띄는" 상황이 생기기 때문입니다.

Skill 측에서는 `disk_utils.zsh`의 alias를 그대로 호출하기도 하고, `dust`, `fd`, `docker`, `ollama` 명령을 직접 조합하기도 합니다. "비활성 Python 가상환경 찾아줘"처럼 alias에 대응하는 함수가 없는 요청은 SKILL.md에 정리된 탐지 패턴(`fd -t d "^\.?venv$"`)을 Claude가 직접 실행합니다.

SKILL.md의 또 다른 역할은 삽질 방지 체크리스트입니다. Docker 이미지의 CREATED 날짜가 빌드 시점이라 pull 시점과 다르다는 점, Colima VM 삭제 후 fstrim을 실행해야 실제 공간이 회수된다는 점, Apple Silicon에서 Colima LaunchAgent 경로가 `/opt/homebrew/bin/colima`여야 한다는 점 등을 주의사항으로 명시해 두었습니다. 에이전트가 이 문서를 컨텍스트로 가져가므로 같은 실수를 반복하지 않습니다.


## 코드 공유 구조

`~/.claude/skills/disk-manager/disk-utils.sh`는 Skill 디렉토리 안에 위치하는 별도 스크립트입니다. 초기 버전의 함수 집합이 여기에 담겨 있고, 실제 운영에서 사용하는 함수는 `~/.oh-my-zsh/custom/disk_utils.zsh`로 발전했습니다.

두 파일의 관계를 정리하면 다음과 같습니다.

| | `disk-utils.sh` | `disk_utils.zsh` |
|---|---|---|
| 위치 | `~/.claude/skills/disk-manager/` | `~/.oh-my-zsh/custom/` |
| 역할 | Skill 번들 동봉 스크립트 | 실제 운영 중인 zsh 플러그인 |
| 캐시 전략 | TTL 내에는 캐시 반환, 만료 시 동기 갱신 | stale-while-revalidate (즉시 반환 + 백그라운드 갱신) |
| 이력 추적 | 없음 | SQLite (`disk_history.db`) |
| 커버리지 | 홈/Library/Documents/Movies | GitHub/iCloud/Colima/Ollama/ML/개발 도구 등 확장 |

`disk_utils.zsh`가 정식 버전입니다. SKILL.md는 이 파일을 "스크립트 위치: `~/.oh-my-zsh/custom/disk_utils.zsh`"로 명시하고, 에이전트가 alias를 호출할 때도 이쪽 함수가 실행됩니다. `disk-utils.sh`는 Skill을 다른 환경에 이식하거나 에이전트가 직접 소스하는 용도로 번들된 상태입니다.

두 파일이 공유하는 핵심 개념은 `_cache_valid()`로 TTL을 판단하는 방식, `~/.disk_cache/`를 캐시 저장소로 사용하는 경로 규칙, 급격한 공간 변화를 `_check_space_change()`로 감지해 캐시를 강제 무효화하는 로직입니다.


## stale-while-revalidate를 셸에 적용한다

`disk_utils.zsh`의 핵심 설계 결정 중 하나는 `_get_or_update_cache()`의 동작 방식입니다.

```zsh
_get_or_update_cache() {
  local cache_file="$1"
  local cmd="$2"

  if [[ -f "$cache_file" ]]; then
    cat "$cache_file"
    if ! _cache_valid "$cache_file"; then
      (eval "$cmd" > "${cache_file}.tmp" && mv "${cache_file}.tmp" "$cache_file") &!
    fi
  else
    eval "$cmd" | tee "$cache_file"
  fi
}
```

파일이 존재하면 TTL 만료 여부와 무관하게 즉시 캐시를 반환합니다. TTL이 지났으면 백그라운드(`&!`)에서 갱신 명령을 실행합니다. 파일 자체가 없을 때만 동기적으로 실행해서 결과를 기다립니다.

이것이 stale-while-revalidate 패턴입니다. 웹에서는 CDN이나 서비스 워커가 캐시된 응답을 먼저 보내고 백그라운드에서 최신 버전을 가져오는 방식으로 동일한 개념을 구현합니다. `dh`를 실행했을 때 `dust`가 홈 디렉토리 전체를 스캔하는 수 초를 기다리지 않아도 되는 이유가 이 구조 때문입니다.

초기 버전(`disk-utils.sh`)에서는 TTL 내에는 캐시를 반환하고 만료되면 동기적으로 재실행했습니다. 응답은 항상 최신이지만, 만료 시점에 터미널이 멈추는 문제가 있었습니다. `disk_utils.zsh`에서 stale-while-revalidate로 전환하면서 응답 지연이 거의 사라졌습니다.

TTL은 `CACHE_TTL=21600`(6시간)으로 설정되어 있습니다. 캐시 파일은 `~/.disk_cache/` 아래에 이름별로 저장됩니다.

```
~/.disk_cache/
  home_usage
  github_usage
  icloud_usage
  appsupport_usage
  libcache_usage
  cache_tools_usage
  .last_used_space       # 급변 감지용 마지막 사용량
  disk_history.db        # SQLite 이력
  refresh.sh             # launchd가 호출하는 스냅샷 스크립트
```

급변 감지는 별도 경로입니다. `_check_space_change()`는 `dh` 실행 시마다 현재 사용량을 `df`로 빠르게 조회하고 `.last_used_space`에 저장된 이전값과 비교합니다. 차이가 `SPACE_THRESHOLD_MB=5120`(5GB)을 초과하면 stale 데이터를 반환하지 않고 캐시 파일을 즉시 삭제합니다. 다음 조회 때 동기적으로 새 데이터를 수집합니다.

```zsh
_invalidate_cache() {
  for f in "$CACHE_DIR"/{home,github,icloud,appsupport,libcache,cache_tools}_usage; do
    rm -f "$f"
  done
}
```

stale-while-revalidate가 "최신성보다 응답 속도 우선"이라면, 급변 감지는 그 예외 조건입니다. 디스크가 5GB 이상 빠르게 줄거나 늘었다면 stale 데이터를 보여주는 비용이 너무 크다고 판단해 동기 갱신으로 전환합니다.


## 운영상 주의

**캐시 신뢰 범위.** `dh`가 보여주는 수치는 캐시 파일 기준입니다. TTL 6시간 이내에 대용량 파일을 내려받거나 삭제했다면 실제값과 다를 수 있습니다. 급변 감지(5GB 임계값)가 잡아주지 못하는 경우에는 `dref`로 캐시를 수동 무효화하거나 `du -sh <디렉토리>`를 직접 실행합니다.

**두 alias 집합의 차이.** `disk-utils.sh`와 `disk_utils.zsh`의 alias가 일부 다릅니다. `disk-utils.sh`의 `dl`은 `disk_library`에, `dd`는 `disk_documents`에 매핑됩니다. `disk_utils.zsh`에는 `dl` alias가 없고 `dgh`, `dicl`, `dcol`, `das`, `dlc`, `dct`가 추가되어 있습니다. 두 파일을 모두 소스하면 alias 충돌이 생깁니다. zsh 플러그인으로는 `disk_utils.zsh`만 소스하는 것이 의도된 사용법입니다.

**Claude Skill 등록.** `~/.claude/skills/disk-manager/SKILL.md`가 있으면 Claude Code가 자동으로 감지합니다. 별도 등록 절차는 없습니다. Skill이 alias를 호출하려면 해당 터미널 세션에서 `disk_utils.zsh`가 소스된 상태여야 합니다. `~/.zshrc`에 `source ~/.oh-my-zsh/custom/disk_utils.zsh`가 포함되어 있지 않으면 에이전트가 `dh`를 실행해도 `command not found`가 납니다. Claude Code가 셸 환경을 상속받는 방식에 따라 다르므로, 에이전트가 alias 대신 `zsh ~/.oh-my-zsh/custom/disk_utils.zsh && dh` 형태로 소스 후 호출하는 패턴이 더 안정적입니다.

**launchd 스냅샷 주기.** `ddiff`와 `dhist`는 스냅샷 기록이 있어야 동작합니다. `dsnap`을 한 번 이상 실행하거나 launchd plist가 등록되어 있어야 합니다. 스냅샷이 없는 상태에서 `ddiff`를 실행하면 "[INFO] 아직 스냅샷 기록이 없습니다" 메시지만 출력됩니다. DB 보관 기간은 90일입니다.

**Docker 정리 후 fstrim.** `dcol`이나 SKILL.md의 Docker 정리 안내를 따라 이미지·볼륨을 삭제한 뒤에는 Colima VM 안에서 fstrim을 실행해야 macOS 파일시스템에 공간이 실제로 반환됩니다.

```bash
colima ssh -- sudo fstrim -av
```

삭제 전후로 `diskutil info / | grep "Container Free Space"`를 비교해 실제 회수량을 확인합니다.


## 참고

- `~/.oh-my-zsh/custom/disk_utils.zsh` — zsh 플러그인 본체
- `~/.claude/skills/disk-manager/SKILL.md` — Claude Skill 정의
- `~/.disk_cache/` — 캐시 저장소 및 SQLite 이력 DB
- `~/Library/LaunchAgents/com.jaesolshin.disk-index.plist` — 6시간 주기 자동 스냅샷
