본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 08. 04:38

모두가 설치하라고 권하는 도구들을 삭제하여 터미널 속도를 7.5배 높인 방법

요약

AI 에이전트가 터미널 명령어를 실행할 때 발생하는 셸 시작 오버헤드를 분석하고, 불필요한 플러그인을 제거하여 속도를 7.5배 개선한 사례를 다룹니다. 에이전트는 매 명령어마다 새로운 셸 프로세스를 생성하므로, 인간 중심의 설정이 에이전트 워크플로우에서는 심각한 비용이 될 수 있음을 경고합니다.

핵심 포인트

  • AI 에이전트는 매 명령어 실행 시 새로운 셸 프로세스를 생성함
  • 인간용 터미널 플러그인은 에이전트에게 반복적인 '세금'으로 작용함
  • 셸 시작 시간을 2.05초에서 0.27초로 단축하여 7.5배 성능 향상
  • 에이전트 워크플로우 최적화 시 셸 초기화 오버헤드 고려 필수

제 셸(shell)의 시작 시간이 2초나 걸렸습니다. 그러다 AI 에이전트가 하루에도 수백 번씩 그 비용을 지불하고 있다는 사실을 깨달았습니다.

지난 15년 동안 조언은 정해져 있었습니다. oh-my-zsh를 설치하고, 몇 가지 플러그인을 추가하며, 자동 완성(autosuggestions) 기능과 예쁜 git 인식 프롬프트(git-aware prompt)를 갖추라는 것이었죠. 이는 터미널을 앞에 두고 앉아 있기에 더 좋게 만들어 주었습니다. 하지만 사람이 앉아서 한 번에 하나의 명령어를 타이핑한다는 그 가정은 이제 대부분의 경우 틀렸습니다.

제 컴퓨터에서는 터미널 명령어의 압도적인 대다수가 제가 아닌 AI 에이전트에 의해 실행됩니다. 그리고 이 관계가 역전되는 순간, 인간의 편의를 위해 설치했던 모든 플러그인은 기계가 당신을 대신해 반복적으로 지불해야 하는 세금(tax)으로 변합니다.

저는 제 설정을 프로파일링(profile)했고, 에이전트 워크플로우(agent workflow)에 아무런 가치를 더하지 않는 도구들을 삭제함으로써 셸 시작 시간을 2.05초에서 0.27초로 — 약 7.5배 — 단축했습니다. 제가 무엇을 발견했는지, 이것이 왜 그 어느 때보다 중요한지, 그리고 어떻게 여러분의 컴퓨터를 감사(audit)할 수 있는지 알려드리겠습니다.

아무도 말해주지 않는 사실: 에이전트는 당신의 셸을 재사용하지 않습니다

당신이 터미널에서 작업할 때는 한 번 열면 됩니다. ~/.zshrc는 단 한 번 실행되고, 시작 비용을 한 번 지불하면, 그 따뜻하게 유지된 세션(session)에서 몇 시간 동안 타이핑을 하면 됩니다. oh-my-zsh를 불러오는(sourcing) 데 시작 시 600ms가 걸린다고 해도 누가 신경 쓰겠습니까? 오전 9시에 한 번 지불하고 잊어버리면 그만이니까요.

AI 에이전트는 그렇게 작동하지 않습니다. 터미널 명령어를 실행하는 에이전트는 일반적으로 **명령어당(또는 작은 배치 단위당) 새로운 셸 프로세스를 생성(spawn)**합니다. 에이전트가 정성스럽게 관리하는 장기 유지 세션(long-lived session) 같은 건 없습니다. git status 실행 → 셸 시작 → 전체 초기화 파일(init) 로드 → 명령어 실행 → 종료. 그다음 bun install 실행 → 완전히 새로운 셸 시작 → 전체 초기화 파일을 다시 로드 → 종료. 모든 명령어가 전체 시작 비용을 매번 다시 지불하는 것입니다.

이제 현대적인 에이전트 도구들이 실제로 어떻게 작동하는지 결합해 봅시다:

  • 병렬 서브 에이전트 (Parallel sub-agents). 복잡한 작업은 여러 에이전트 스레드에 걸쳐 동시에 전개됩니다. 하나는 컨텍스트를 수집하고, 하나는 테스트를 실행하며, 다른 하나는 파일을 편집합니다. 각각 자체 셸을 생성합니다.
  • 백그라운드 프로세스 (Background processes). 개발 서버(Dev servers), 워처(watchers), 테스트 러너(test runners)가 자체 셸 인스턴스를 가집니다.
  • 재시도 및 검증 루프 (Retry and verification loops). 명령을 실행하고, 출력을 확인하고, 수정하고, 다시 실행합니다. 더 많은 셸이 필요합니다.

따라서 비용은 startup_time이 아닙니다. 다음과 같습니다:

startup_time × commands_per_task × parallel_agents

제가 줄인 1.78초는 한 번 절약되는 것이 아니라, 모든 에이전트 스레드의 모든 셸 생성 시마다, 매일 절약됩니다.

대략적인 예시를 들자면: 50개의 명령을 실행하는 에이전트 작업은 실제 작업을 수행하기 전에 오직 '셸 시작'만으로 약 100초를 소모했습니다. 만약 큰 작업을 위해 세 개의 에이전트를 병렬로 실행한다면, 순수 초기화 오버헤드(init overhead)로 몇 분을 날리는 것이며, 여기에 CPU와 배터리까지 소모합니다.

프로파일링을 통해 알게 된 것들

저는 zsh의 내장 프로파일러를 사용하여 셸당 2초가 어디에 쓰이는지 확인했습니다:

# ~/.zshrc 맨 위에 임시로 추가하세요
zmodload zsh/zprof
# ... 나머지 설정 ...
...

새로운 셸을 열고 표를 읽어보세요. 결과는 거의 우스꽝스러울 정도로 한쪽으로 치우쳐 있었습니다.

문제의 원인 #1: Yandex Cloud CLI의 완성 스크립트 — 827ms (총 시간의 52%)

가장 큰 비용을 차지한 것은 심지어

이것이 문제의 가장 순수한 형태입니다. 탭 완성 (Tab-completion) 기능은 '직접 타이핑하고 Tab 키를 누르는' _사람_에게는 도움이 됩니다. 하지만 에이전트 (Agent)는 언어 모델 (Language Model)로부터 전체 명령 문자열을 한 번에 생성합니다. 에이전트는 결코 Tab 키를 누르지 않습니다. 이 기능의 전체 가치 제안 (Value proposition)은 셸 (Shell)의 주요 사용자와 무관함에도 불구하고, 시작 경로 (Startup path)에서 가장 많은 비용을 차지하고 있었습니다.

가해자 #2: 완성 프레임워크 자체 — 약 640ms

oh-my-zsh의 메커니즘 (compinit, compdump, 그리고 약 2,500개의 compdef 호출)이 나머지 비용의 대부분을 차지했습니다. compinit은 완성 캐시 (Completion cache)를 재구축하고 완성 디렉토리에 대해 보안 감사 (Security audit)를 실행합니다. 셸 환경에서 직접 작업한다면 유용하겠지만, 모델이 명령어를 생성하는 상황에서는 불필요한 짐 (Dead weight)일 뿐입니다.

가해자 #3: Forge의 셸 플러그인

아이러니하게도, 다른 AI 코딩 도구인 Forge (CLI 에이전트)가 자체적인 zsh 플러그인(명령어, 완성, 키 바인딩)을 설치해 두었으며, 이것이 실행 경로 (Hot path) 내에서 eval "$(forge zsh plugin)"을 통해 매 실행 시마다 작동하고 있었습니다. AI 도구가 인간의 속도를 높이기 위해 셸 상호작용 (Shell-interactivity) 기능을 추가함으로써, 정작 명령어를 실행하는 AI 도구 자체의 속도를 늦추고 있었던 것입니다.

정리 과정, 영향도 순서대로

저는 각 단계마다 측정하며 비용이 높은 순서대로 항목들을 제거했습니다:

단계제거한 항목시작 시간
기준점 (Baseline)2.05s
...

단순히 "무언가를 삭제하는 것"을 넘어, 논리적으로 추론할 수 있게 해주는 몇 가지 세부 사항은 다음과 같습니다:

대화형(Interactive) 셸과 비대화형(Non-interactive) 셸의 차이가 중요합니다. 히스토리 확장 (커밋 메시지를 망가뜨리는 ! 기호), 완성 (Completion), 그리고 프롬프트 테마 (Prompt theming)는 대화형 기능이며, 오직 대화형 셸에서만 로드됩니다. 이러한 기능들이 에이전트에게 영향을 주었다는 사실 자체가, 에이전트가 ~/.zshrc를 불러오는(source) 대화형 셸을 실행하고 있었음을 확인시켜 주었으며, 이것이 바로 파일을 다듬는 것이 명령어당 비용을 줄이는 데 효과적이었던 이유입니다.

도구를 삭제한다는 것은 그것에 의존하던 것들도 함께 삭제됨을 의미합니다. 제가 oh-my-zsh를 삭제했을 때, Forge의 플러그인에서 command not found: compdef 오류가 발생하기 시작했습니다. oh-my-zsh가 자동 완성 시스템 (completion system)을 초기화하고 있었고, Forge는 이를 통해 자신의 자동 완성 기능을 등록했기 때문입니다. 프레임워크를 그냥 뽑아버릴 수는 없습니다. 의존성 항목들이 필요로 하는 단 하나의 기본 요소(가벼운 compinit)를 복구하거나, 아니면 의존성 항목들도 함께 제거해야 합니다. (저는 결국 Forge와 자동 완성 기능을 모두 제거했습니다.)

캐시 로직은 거꾸로 구현하기 쉽습니다.

인간의 편의를 위한 기능 중 에이전트 (Agent)에게 도움이 되는 것은 거의 없으며, 오히려 몇몇 기능은 적극적으로 방해가 됩니다. git log 실행 시 less를 열고 키 입력을 기다리는 페이저 (Pager)는 에이전트를 무기한 대기 상태로 만듭니다. 에이전트는 출력이 없다고 판단하고 타임아웃 (Timeout)이 발생할 때까지 멈춰 있게 됩니다. -m 옵션 없이 커밋을 시도할 때 팝업되는 에디터 (Editor)는 오지 않을 인간을 영원히 기다립니다. 일치하는 항목이 없을 때 에러를 발생시키는 글로브 (Glob)는 에이전트가 성공할 것이라고 예상했던 명령을 중단시켜 버립니다.

따라서 속도를 높이기 위해 수행한 동일한 감사 (Audit) 과정은 에이전트에게 올바른 환경을 만들어 주기도 합니다:

# Non-blocking defaults — nothing waits for a human
export PAGER=cat
export GIT_PAGER=cat
...

이것들은 엄밀히 말해 속도 최적화라기보다는, "에이전트가 멈춰서 대기 상태를 복구하느라 토큰 (Tokens)을 낭비하는 것을 방지하는" 수정 사항입니다. 에이전트 중심의 워크플로우 (Agentic workflow)에서 차단된 명령은 느린 명령보다 더 나쁩니다. 단순히 시간만 소모하는 것이 아니라, 모델이 왜 응답을 받지 못했는지 파악하려고 시도하는 동안 컨텍스트 (Context)와 토큰을 소모하며, 종종 다른 도구들을 휘두르며 허우적거리게 만들기 때문입니다.

셸 (Shell)뿐만이 아닙니다 — IDE의 전체 표면이 대상입니다

동일한 논리가 ~/.zshrc 너머로 확장됩니다.

파일 워처 (File watcher). 제 에디터는 약 163,000개의 파일을 감시하고 있었으며, 그중 64,000개는 node_modules에 있었습니다. 파일 워처는 파일이 변경될 때 UI를 업데이트하기 위해 존재하지만, 에이전트는 끊임없이 파일을 변경하며 자신이 변경했다는 것을 알기 위해 워처가 필요하지 않습니다. 스스로 변경을 수행했기 때문입니다. node_modules, 빌드 결과물, 캐시 (Caches)를 제외하면 지속적인 CPU/메모리 소모를 제거할 수 있으며, 결정적으로 저장을 지연시킬 수 있는 이벤트 큐 (Event-queue) 지연을 제거할 수 있습니다.

// settings.json
"files.watcherExclude": {
  "**/node_modules/**": true,
...
}

더티 버퍼 (Dirty-buffer) 충돌. 자동 저장 (Auto-save) 기능이 없다면, 에이전트가 파일을 직접 수정하는 순간 인간의 저장되지 않은 에디터 버퍼와 디스크 상의 파일이 서로 어긋나게 됩니다. 그러면 "저장 / 되돌리기 / 덮어쓰기" 충돌 프롬프트가 나타나며, 에이전트는 오래되었거나 충돌하는 콘텐츠를 보고 스스로를 의심하며 턴 (Turns)을 낭비하게 됩니다. 공격적인 자동 저장은 디스크와 버퍼를 동기화하여 충돌이 발생하지 않도록 유지합니다.

"files.autoSave": "afterDelay",
"files.autoSaveDelay": 1000

이것은 순수하게 에이전트 시대(agent-era)의 실패 모드입니다. 편집과 저장을 동일한 사람이 수행하는 인간 중심의 워크플로우(human-only workflow)에서는 말 그대로 발생할 수 없는 일입니다.

자신의 설정을 감사(Audit)하는 방법

  1. 추측하지 말고 프로파일링(Profile) 하세요. 상단에 zmodload zsh/zprof를, 하단에 zprof를 추가한 뒤 셸을 열어 표를 읽으세요. 문제를 일으키는 주범은 여러분이 예상하는 것과 거의 일치하지 않습니다.
  2. 정직하게 시간을 측정하세요: for i in 1 2 3; do /usr/bin/time -p zsh -i -c exit; done. 가벼운 설정은 0.3초보다 훨씬 빠릅니다. 1초가 넘는다면 문제가 있는 것입니다.
  3. 영향도에 따라 삭제하세요. 프로파일에서 가장 긴 줄부터 시작하세요. 무엇이 실제로 지표를 변화시켰는지 알 수 있도록 삭제할 때마다 다시 측정하세요.
  4. 프레임워크뿐만 아니라 의존성(Dependents)도 제거하세요. 삭제한 항목에 연결된 모든 것은 명시적 혹은 암묵적으로 오류를 일으킬 것입니다. 원시 기능(Primitive)이 필요한지, 아니면 의존 항목이 필요한지 결정하세요.
  5. 비차단(Non-blocking) 방식으로 만드세요. 페이저(Pager)는 cat으로, 에디터(Editor)는 아무 작업도 하지 않도록(no-op) 설정하고, 히스토리 확장(History expansion)을 비활성화하며, 일치하지 않는 글로브(Globs) 패턴에서 에러가 발생하지 않도록 하세요. 단순히 속도뿐만 아니라, 비대화형 호출자(Non-interactive caller)를 위한 정확성을 확보해야 합니다.
  6. IDE까지 확장하세요. 와처(Watcher)와 검색 대상에서 무거운 디렉토리를 제외하세요. 에이전트의 편집이 오래된 버퍼(Stale buffers)와 충돌하지 않도록 자동 저장(Auto-save)을 켜두세요.

핵심 요약 (The takeaway)

oh-my-zsh, 화려한 프롬프트(Fancy prompts), 그리고 자동 완성 프레임워크(Completion frameworks)는 나쁜 도구가 아니었습니다. 그것들은 그 시대에 적합했습니다 — 즉, 한 명의 인간이 하나의 장기 실행되는 터미널 앞에 앉아 있었고, 시작 비용(Startup cost)이 거의 무시할 수 있는 수준이었던 시대 말입니다. 그 시대는 끝나가고 있습니다. AI 에이전트가 병렬 스레드(Parallel threads)를 통해 수백 개의 수명이 짧은 셸(Short-lived shells)을 생성할 때, 계산 방식은 완전히 뒤집힙니다. 한 번의 편의성이 명령당 세금(Per-command tax)이 되어 여러분의 동시성(Concurrency)만큼 배수로 불어나게 됩니다.

해결책은 도구 사용 자체를 반대하는 것이 아닙니다. 여러분의 도구가 현재 실제로 누구를 위해 봉사하고 있는지를 인식하는 것입니다. 제 터미널이 7.5배 빨라진 것은 어떤 영리한 기술 덕분이 아니라, 더 이상 거의 존재하지 않는 사용자를 위해 최적화하는 것을 멈추고, 대부분의 작업을 수행하는 사용자를 위해 최적화하기 시작했기 때문입니다.

만약 어떤 프로그램이 당신의 명령어를 입력하고 있다면, 그 프로그램에 필요한 환경 — 빠르고, 논블로킹 (non-blocking)이며, 문자 그대로의 (literal) 환경 — 을 구축하십시오. 그리고 인간을 위한 편의 계층 (human-comfort layer)은 당신이 실제로 운전석에 앉아 있는 드문 순간들을 위해서만 남겨두십시오.

에이전트 워크플로 (agent workflow)를 위해 쉘 (shell)을 비워보셨나요? zprof에서 가장 큰 원인을 차지했던 것은 무엇이었나요? 여러분의 전후 수치를 댓글로 남겨주세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0