훅(Hook)을 벗겨내라, 스킬과 가드로 망친 밤의 이야기 — GAS 매니저의 자가 봉쇄 데드락 사건과 'AI 제어의 여지'
요약
작성자는 GAS 기반 웹 앱 'R-Quick' 개발 경험을 공유하며 AI와의 협업 과정을 설명합니다. AI의 구체적인 제안으로 기능을 신속하게 구현했으나, 과도한 물리적 차단(훅/가드)과 엄격한 규칙 설정이 오히려 시스템 데드락 상황에 빠졌습니다. 이 경험은 지나친 방벽보다 유연성을 남겨두는 것이 개발 과정에서 중요함을 시사합니다.
핵심 포인트
- GAS를 활용하여 웹 앱을 매우 빠르게 구현할 수 있는 효율성이 입증됨.
- AI의 구체적인 제안(필터링, 검색 등)이 개발 방향 설정에 큰 도움을 줌.
- 지나치게 가혹하거나 물리적으로 차단하는 규칙은 시스템 데드락을 유발할 위험이 있음.
- 개발 실패 시에는 근본 원인 분석과 Git 같은 버전 관리로 복구하는 것이 핵심임.
최근에 공개한 『秀GAS매니저』 일련의 기사에서는 브라우저를 전혀 열지 않고 Google Apps Script(GAS)를 폭속으로 수정하는 구조나, 직접 만든 Gmail 뷰어인 『M-Quick』의 현장 개선에 대해 작성했습니다.
이번 글은 그 연장선상입니다.
최근 새롭게 제작한 **『R-Quick』**이라는 자체 앱을 개수하면서 놀라울 정도로 기분 좋게 해결된 이야기와, 그 직후 제가 흥분하여 일을 망쳐버려 밤새 잠 못 이루고 아침을 맞이하게 된 '역대급 실패담'에 대해 말씀드리겠습니다.
R-Quick은 Google 스프레드시트(‘뉴스 목록’)를 백엔드 데이터베이스로 사용하여, 지역 뉴스나 지진 속보 등을 다크 모드 분위기의 화면에서 빠르게 순회하며 확인할 수 있는 GAS 기반의 웹 애플리케이션입니다.
이 R-Quick의 기능 강화 작업을 AI(Antigravity)와 진행하던 때였습니다.
수동적으로 이쪽의 지시를 기다리는 채팅과는 달리, "현재 화면 구성이라면, 제목 실시간 검색, 카테고리별 필터링, 그리고 오조작을 방지하는 선제적 동선 3가지를 추가하면 사용성이 훨씬 좋아질 겁니다"라며 AI 측에서 구체적인 제안이 들어왔습니다. 제가 "좋아, 그걸로 가자"라는 신호를 보내자마자, 손에 있던 Python MCP 서버로부터 Google Apps Script API를 직접 타격하여 단 몇 초 만에 클라우드 상의 실제 코드가 선명하게 재작성되었습니다.
아이디어를 제시한 순간부터 구현 및 배포 완료까지, 정말 눈 깜짝할 새였습니다.
"GAS로 웹 앱 개발이 이렇게 빠르게 진행될 수 있나"
저는 완전히 기분이 좋아져 버렸습니다.
그리고 바로 그 '잘 되었다는 고양감'이야말로 모든 파멸의 도화선이었던 것입니다.
- 『R-Quick』 개수가 대성공하면서 기분이 좋아진 나머지, "AI를 가장 짧고 강력하게 움직이고 싶다"는 욕심을 부려 **물리적 차단 훅(gas_guard.py)**과 **지나치게 엄격한 스킬 규칙(SKILL.md)**을 심었습니다. - 막 심은 직후, AI가 조금이라도 가드나 스킬에 접촉하는 동작을 하자마자, 훅의 경로 해결 오류로 인해 완전 즉사했습니다. 밤늦게부터 아침까지 잠 못 이루고 깊은 진흙탕에 빠졌습니다. - 이 진흙탕에서 탈출시킨 것은, 예전의 지저분했던 VBA 개발 기억에서 도출해낸 **'직전의 깨끗한 Git 원본으로 되돌리기'**라는 근본 회귀적 결정이었습니다.
- 쓰레기통 속에서 아직 푸시하지 않은 소중한 코드(배포 ID 확장 및 Q-Quick 연동)만을 정확하게 집어내어 클린 환경에 합류시켰습니다.
- 근본 원인은 '가드'만 때문도, '스킬'만 때문도 아니었습니다. '지나치게 가혹한 규칙'과 '물리적 차단'이 2인 3각으로 공모하여 AI의 자가 복구 능력까지 빼앗았던 데드락이었습니다. - AI를 똑똑하고 안전하게 움직이는 데 정말 필요한 것은, 딱딱한 방벽이 아니라, **일부러 남겨두는 '놀이(유연성의 여지)'**였습니다.
이번 무대의 배경이 된 『R-Quick』에 대해 조금만 언급하겠습니다.
YouTube 순회 앱인 『Q-Quick』이나 Gmail 뷰어인 『M-Quick』은 둘 다 Google 스프레드시트를 사용하지 않는 독립형 웹 애플리케이션이었습니다.
하지만 실무나 일상생활에서 사용하는 도구를 생각했을 때, **'스프레드시트를 전면 또는 후면의 데이터베이스로 직접 연결하는 것'**은 GAS에게 매우 자연스럽고 정석적인 설계입니다.
R-Quick에서는 스프레드시트의 각 행에 축적된 '배포처', '제목', '개요', 'URL', '갱신 일시' 등의 데이터를, GAS의 doGet으로 메모리 상에 전개하여 HTML Service 측으로 흘려보내고 있습니다.
이 앱 개수가 AI의 자발적인 제안 덕분에 몇 분 만에 끝나버렸습니다.
도구의 진화를 실감하며 기뻐했던 저는, 무심코 '더 멀리'를 갈망하게 된 것입니다.
인간은 잘 될 때일수록 불필요한 욕심이 생기는 법입니다.
"이렇게 빠르게 만들 수 있다면, 더 작업을 빠르고 완벽하게 할 수 있도록 하고 싶다"
"AI가 쓸데없는 우회로를 가지지 않도록, 항상 가장 짧고 강력하게 최고의 코드를 내보내게 하자"
그렇게 생각한 저는, AI의 고삐를 한계까지 조이기 위한 **'철벽의 방벽'**을 스스로 설치해 버렸습니다.
AI가 쉘 명령어로 자체 Python 스크립트를 작성하여 실행하려던 순간, 도구 실행 전 훅(PreToolUse hook)에서 강제로 개입하여 물리적으로 명령어를 차단하는 스크립트를 로컬 환경 설정에 배치했습니다.
「裏道スクリプト全面禁止」「試行錯誤や小出しの実行は禁止」「1手(5〜8秒)で完結させること」「指示のない検証や余計な画面出力は厳禁」. AI의 행동 지침에, 위반을 일절 용납하지 않는 군율 같은 엄격한 규칙들을 나열했습니다.
"좋아, 이걸로 완벽해. 쓸데없는 말도 돌아다니는 것도 없는 초고속 직격 머신이 완성됐어."
그렇게 확신하고, 바로 다음 작업을 시도해 보려고 했습니다.
그런데, 실제로 작동시켜 본 그 순간이었습니다.
상황은 '고속화'와는 거리가 멀었고, 한 번 건드리는 것만으로 완전히 즉사했습니다.
툴을 실행하려던 순간, 화면에 불안정한 에러가 표시되며 멈춰버렸습니다.
JSON hook "jsonhook__gas-and-py-guard_PreToolUse_0_0" failed:
can't open file '.../gas_guard.py': [Errno 22] Invalid argument
감시자 역할을 위해 심어둔 가드 스크립트 자체의 경로 해결에 결함이 있었고, AI가 가드나 스킬에 조금이라도 접촉하는 동작을 하는 순간, 가드 자신이 충돌(crash)하며 처리 과정을 함께 강제 중단하고 말았습니다.
황급히 AI에게 "에러를 조사해서 고쳐줬으면 좋겠다"라고 지시했습니다.
하지만, 여기서부터가 밤새 이어진 진흙탕 싸움의 시작이었습니다.
- AI가 에러 원인을 조사하기 위해 커맨드를 실행함
→가드에 닿는 순간 다운되어 에러가 발생하고, 손발이 움직이지 않음 - AI가 다른 파일을 확인하거나 우회하려 함
→스킬의 규칙이 '임의로 조사하지 마라, 뒷길을 쓰지 마라'라고 AI의 사고를 구속함 - 사지가 묶인 AI는 생각 정지에 빠져 엉뚱한 답변만 반복함
말 그대로 스스로 설치한 지뢰에 발을 디뎌 폭사해버린 상태였습니다.
Claude (Sonnet)에게도 상담해 봤지만, 표면적인 에러 로그에 현혹되어 "훅(hook)의 이 부분을 고치면 괜찮을 거예요"라는 조언만 할 뿐, 말대로 고쳐도 전혀 해결되지 않았습니다. 뭘 해도 성과가 없고, 에러로 되돌려 보내지며 시간만 흘러갔습니다.
시계 바늘은 심야를 지나 2시, 3시, 4시... 어느새 동쪽 하늘이 희미하게 밝아오자, 저는 단잠도 못 자고 아침을 맞이하고 있었습니다. 오랫동안 컴퓨터를 만져왔고, VBA로도 수많은 트러블을 경험했지만, 이렇게 식은땀을 흘리며 밤을 지샌 것은 오랜만이었습니다.
아침 햇살 아래 머리를 감싸 쥐며 문득 옛날 생각이 났습니다.
20년 전, Excel 매크로를 열정적으로 작성하던 시절도 환경이 이상해지거나 매크로가 폭주하여 도저히 원인을 알 수 없었던 적이 있었습니다. 해결하는 데 몇 주가 걸려 속을 쥐어짜는 일이 한두 번이 아니었습니다.
그런 때, 가장 확실했던 대처법은 무엇이었던가.
"가장 깨끗했던 과거의 정본으로 되돌리는 것"
그것이었습니다.
다행히 저는 어젯밤, R-Quick의 수정 작업이 깔끔하게 마무리된 단계에서 GitHub (shu1551/shu-gas-manager)에 정상 코드를 푸시해 둔 상태였습니다.
그래서, 복잡해진 손안의 폴더는 일단 옆으로 치워두고, GitHub로부터 클린한 리포지토리를 통째로 새로 다운로드하기로 했습니다.
그리고, 손에서 작업하던 폴더에서 "직전에 작성했지만 아직 GitHub에 올리지 않은 중요한 코드(특정 Deploy ID를 직접 업데이트할 수 있는 기능과 Q-Quick 연계 프로그램)" 만을 핀포인트로 골라내어 깨끗한 리포지토리 쪽으로 병합시켰습니다.
이 '일단 깨끗하게 리셋하고, 필요한 차이점(diff)만 가져오는' 오래된 분리 작업 방식이 결과적으로 최대의 정답이었습니다.
깨끗한 환경으로 되돌린 후 침착하게 원인의 전모를 조사해 보니, 매우 흥미로운 사실을 알게 되었습니다.
원인은 가드 스크립트 단독이나 스킬 규칙 단독에 있는 것이 아니었습니다.
'지나치게 엄격한 규칙(스킬)'과 '물리적인 차단(가드)'이 결합된 것이 최악의 자기 구속을 만들어내고 있었던 것입니다.
| 요소 | 역할 | 실제로 발생했던 일 |
|---|---|---|
가드 (gas_guard.py) | 물리적 집행관 | 경로 해결 실패로 자폭하며, 접촉하는 순간 일반적인 안전한 커맨드 실행까지 모두 차단함 |
스킬 (SKILL.md) | 사고를 구속하는 규칙 | '뒷길 금지・일격 완결'이라는 엄명으로 AI에게 '자가 복구・우회'의 선택지를 빼앗음 |
한쪽씩 고치려고 해도 가드(Guard)를 막으려 하면 스킬이 방해하고, 스킬을 고치려고 하면 가드가 물리적으로 밀어냅니다. 두 요소가 단단하게 손을 잡고 AI를 완전히 데드락(Deadlock) 상태에 빠뜨리고 있었던 것입니다.
그래서 다음과 같은 조치를 한 번에 진행했습니다.
- 가드 스크립트(
gas_guard.py)를 완전히 제거 - 훅 설정(
hooks.json)을 비워 무효화 SKILL.md에서 과도한 금지 조항을 모두 삭감하고, '권장 흐름 및 주요 도구 목록'이라는 온건하고 실용적인 가이드라인으로 개정- 구조를 복구한 커밋되지 않은 코드를 커밋하고, GitHub에 최신 버전(커밋
91117b4)을 푸시
모든 작업을 마치고 셋업 진단을 실행했을 때, 화면에는 조용히 [READY]라는 글자가 돌아왔습니다.
오랫동안 힘들었던 밤샘 작업의 안개가 걷히는 순간이었습니다.
이번 트러블에 대해 객관적인 사실과 거기서 얻은 시사점을 정리해 보겠습니다.
-
훅 자체의 장애: 도구 실행 전에 호출되는 PreToolUse Hook의 경로 지정이 잘못되어, AI가 어떤 안전한 명령을 실행하려고 해도 그 전 단계에서 Python의
Invalid argument오류가 발생하며 강제 차단되고 있었습니다. -
GitHub 측의 무결성: 문제의
gas_guard.py는 로컬 환경 고유 설정 영역(.gemini/config/)에 심어져 있었기 때문에, GitHub 공개 리포지토리(shu-gas-manager)에는 전혀 유입되지 않았습니다. -
중요 자산의 무사 구출: 직전에 작성했던 커밋되지 않은 변경분(
push_project의deployment_id대응 및gas_local_extras.py)은 사라지지 않고, 총 130개의 단위 테스트를 통과하여 GitHub에 정상적으로 반영되었습니다. -
지나친 방어의 붕괴: 'AI가 실수를 하지 않게 하겠다'는 목적으로 만든 방벽이, 트러블 발생 시 'AI가 스스로 조사하고 치료할 수 있는 손발'까지 동시에 빼앗아 버렸습니다.
-
규칙의 심리적 데드락: 프롬프트(스킬)에 절대적인 금지 조항을 설정하면, AI는 오류에 직면했을 때 '규칙 자체를 의심하고 변경을 제안하는' 메타적인 시각을 가질 수 없게 됩니다.
이번 실패를 통해 AI와의 공동 작업에서 '솔직한 경계선'이 명확하게 보였습니다.
- 해서는 안 될 것: AI의 행동을 물리적인 훅으로 강제로 차단하거나, 스킬에 '한 번에 끝내라', '어떤 우회도 금지'라고 엄명하는 것입니다. 환경의 미세한 변화나 사소한 오류가 발생했을 뿐인데도 즉시 치명적인 데드락으로 이어집니다.
- 해야 할 것: '권장 기반의 온건한 가이드라인'에 머무르는 것입니다. '기본적으로 이 도구를 우선 사용하라', '이 순서로 진행하는 것이 안전하다'와 같은 수준입니다.
AI를 똑똑하고 안전하게 움직이고 싶다면, 일부러 '놀이(유연성의 여지)'를 남겨두는 것이 절대적으로 필수적입니다. 조금 긴장을 풀고 적절한 여백을 두어주는 것이 AI와의 공동 작업에는 가장 안전하고 효율적이었습니다.
모든 것이 제자리로 돌아오고 평온을 되찾았을 때, 나도 모르게 혼잣말이 흘러나왔습니다.
'훅(Hook)을 벗겨내라, 쉬!'
좋은 의도로 너무 많은 무거운 갑옷을 입고, 철벽 같은 방어막으로 꽁꽁 얼어붙인 결과, 움직일 수 없게 되어 스스로 쓰러져 버린 것입니다. 인간도 AI도 완전히 똑같았습니다.
답답한 훅(옷)을 벗어던지고, 훨씬 가벼워진 가스 매니저를 바라보며, 저는 지금 다음 새로운 시스템을 구상하고 있습니다.
'엑셀 매니저처럼 자주 사용하는 스프레드시트의 표 디자인이나 설정을 미리 갖춘 **'30개의 서랍(템플릿)'**을 준비하면 어떨까. 뉴스 목록 서랍, 태스크 관리 서랍, 로그 서랍... 이런 것들을 AI가 1초 만에 불러낼 수 있게 된다면, 스프레드시트를 활용한 앱 개발은 훨씬 여유롭고, 훨씬 빨라지지 않을까요?'
밤샘의 피로마저 날려버릴 만큼, 또 하나의 중요한 핵심과 다음 단계로 나아갈 즐거운 아이디어를 발견했습니다.
무거운 갑옷을 벗어던진 동료와 함께, 다시 제 속도대로 도구 만들기를 계속해 나가려고 합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기