나는 계속 긴 에이전트 작업을 실행시켜 놓고, 마치 그게 나한테 빚진 게 있는 것처럼 터미널 위를 맴돌았다. 죽은 시간이 쌓여갔다. 그래서 내가 지켜보지 않아도 터미널을 대신 지켜봐 주는 작은 도구를 만들었다.

부끄러운 부분은 여기다. 나는 AI 에이전트에게 진짜 작업을 맡겼다, 인증 모듈 리팩터링, 라우트 마이그레이션, 전체 테스트 스위트 실행, 그러고는 그냥… 지켜봤다. 6분짜리 진행 스피너를, 눈을 떼면 그게 도망갈 것처럼 노려보면서.
대안은 더 나빴다. Slack으로 탭을 넘겨 다른 일에 빠졌다가, 에이전트가 이미 끝나고 식어버린 지 10분 뒤에야 다시 돌아왔다. 그때쯤이면 내가 뭘 물어봤는지 맥락을 이미 놓친 뒤였다.
그래서 실행은 6분 걸렸지만, 나한테는 15분이 들었다. 매번. 시작과 완료 사이의 그 간격이, 조용히 내 하루를 갉아먹고 있었다.
🔔 신호는 이미 거기 있었다
짜증나는 건, 내가 알고 싶었던 그 순간이 이미 존재한다는 거다. 모든 에이전트는 자기가 한 턴을 끝냈는지, 아니면 멈춰서 뭔가 물어보려는지 정확히 안다. Claude Code는 Stop 훅을 발동시킨다. Codex에는 notify 커맨드가 있다. Gemini에는 AfterAgent 이벤트가 있다. Copilot에는 agentStop이 있다.
이벤트는 각 도구 안에 이미 앉아 있었다. 아무도 그걸 단순한 *"어이, 돌아와"*로 바꾸지 않았을 뿐이다.
그 프레이밍이 나를 불평 대신 만들기로 옮기게 했다. 뭔가를 폴링하거나 로그를 긁어올 필요는 없었다. 에이전트가 이미 방송하고 있던 신호를 붙잡아서, 음성과 알림과 소리로 바꾸기만 하면 됐다. 내가 어디로 떠돌아갔든 나에게 닿는 넛지 하나. 그걸 해주는 게 turnbell이다.

🧱 첫 번째 결정은 기능이 아니라 제약이었다
한 줄도 쓰기 전에, 나는 이 도구가 하면 안 되는 것부터 정했다.
내 프로세스 목록에서 웅웅거리는 백그라운드 데몬은 없다. 모든 프로젝트에 임포트해야 하는 SDK도 없다. 뭘 건드리고 있는지 불안하게 만드는 것도 없다. 각 에이전트 자신의 훅 설정을 명령어 하나를 호출하도록 배선할 뿐이고, 그게 전체 발자국이다.
거기서 규칙 두 개가 나왔다.
- 모든 변경은 바이트 단위로 되돌릴 수 있다. turnbell(npm에도 있다)은 설정 수정을 원자적으로 적용한 다음, 방금 쓴 내용의 정확한 diff를 보여주고 그 자리에서 유지하거나 되돌릴 수 있게 한다. 건드리지 않은 파일은 이전과 정확히 같은 바이트로 복원된다. 블록만 주입한 파일(에이전트의 지침 파일 같은 것)은 그 블록만 다시 벗겨내므로, 그 뒤에 주변을 직접 편집했더라도 그 편집은 그대로 남는다.
- 제거는 정직해야 한다. 위의 두 규칙을 그대로 써서 자신이 추가한 것만 정확히 되돌리고 그 이상은 건드리지 않는다, 그래야 되돌릴 수 있다고 주장해 놓고 조용히 그렇지 않은 상황이 생기지 않는다.
진짜 엔지니어링의 대부분은 여기, 이 화려하지 않은 약속에 들어갔다. 이 도구가 당신의 기기를 발견했을 때와 정확히 똑같은 상태로 남겨두겠다는 약속. 전역 설정을 건드리는 도구라면 그 접근 권한을 스스로 증명해야 한다.
🔒 기기를 떠나는 단 하나
휴대폰 알림을 원했는데, 그건 뭔가가 네트워크를 타야 한다는 뜻이었다. 그래서 나는 덜 조심스러워진 게 아니라 더 조심스러워졌다.
음성, 데스크톱 알림, 소리는 정의상 로컬이라 절대 기기를 떠나지 않는다. 나가는 경로는 선택적인 웹훅 하나뿐이고, 거기엔 정확히 여섯 개 필드만 내보내는 시리얼라이저가 하나 있다. 버전, 타임스탬프, 에이전트 이름, 이벤트, 프로젝트 폴더 이름, 짧은 상태 줄.
코드는 없다. 작업 디렉토리도 없다. 에이전트의 응답도 없다. 그리고 신뢰하기 전에 정확한 바이트를 미리 출력해볼 수도 있다. 플래그 하나면 페이로드를 보여주고 아무것도 보내지 않는다.
프라이버시는 마지막에 갖다 붙인 마케팅 문구가 아니었다. 구조적인 선택이었다. 네트워크에 문 하나만 주고, 그 문을 작게 만드는 것.
🧩 여덟 개 에이전트, 하나의 계약
그다음엔 지저분한 중간 지대가 왔다, 대개 흥미로운 작업이 숨어 있는 곳.
모든 에이전트는 서로 다른 권한을 가진 다른 훅 집합을 노출한다. Claude Code는 뭐든 다 할 수 있다. 완료, 차단, 소리 내어 읽기, 슬래시 커맨드. Cursor는 끝났다는 것만 알릴 수 있다. opencode는 자기 트랜스크립트를 노출할 수 없어서, 응답을 소리 내어 읽는 건 애초에 선택지에서 빠진다.
이걸 덮어버리고 균일한 지원을 주장하고 싶은 유혹이 있다. 나는 반대로 했다. 에이전트마다 하나의 어댑터를 만들어 단일한 wire/unwire 계약 뒤에 두었고, 기능 표는 각 에이전트가 실제로 뭘 해낼 수 있는지 있는 그대로의 진실을 말해준다.
누군가의 신뢰를 잃는 가장 빠른 방법은, 그 사람의 설정으로는 감당할 수 없는 기능을 약속하는 거니까. 정직한 한계가 거짓말하는 예쁜 표보다 낫다.
🎯 실제로 배운 것
재미있던 부분은 말하는 터미널이 아니었다. 그 주변의 모든 것이었다.
진짜 문제는, 당신의 전역 설정과, 당신의 에이전트와, 당신의 기기 안으로 손을 뻗으면서도 거기 있을 자격이 있는 뭔가를 만드는 것이었다. 원자적으로 적용하고, 되돌릴 수 있게 만들고, 네트워크에는 작은 문 하나만 주고, 할 수 없는 건 소리 내어 말하기.
나는 계속 테스트 하나로 돌아왔다. 제거하는 사람이 지켜보고 있다고 생각하고 만들어라. 그 렌즈 하나가 어떤 기능 요청보다도 더 많은 설계 결정을 내려줬다.
요즘 나는 긴 실행을 시작하고 실제로 자리를 뜬다. 몇 분 뒤 내 노트북이 응답을 소리 내어 읽어주거나, 에이전트가 막혀서 결정이 필요할 때 내 휴대폰이 울린다. 죽은 시간은 사라졌다. 나는 중요한 순간에 정확히 불려 돌아온다, 1분 먼저도 아니고, 10분 늦게도 아니고.
되돌릴 수 있는 설정 편집과 문 하나뿐인 네트워크 정책이 마음에 든다면: turnbell은 오픈소스다: GitHub · npm.
되돌릴 수 없는 걸로 밝혀지면 당장 신뢰를 접을 설정 편집 도구가 있다면, 그건 뭔가?
당신에게 이미 그런 일이 있었는지 궁금하다, 닷파일을 다시 쓰고 돌아갈 길을 남기지 않은 어떤 CLI, 그리고 그게 그 이후로 인스톨러의 약속을 얼마나 꼼꼼히 읽게 만들었는지도.


