실제 터미널 캡처: grok --version과 grok --help에서 --always-approve, --cwd, --max-turns, --prompt-file 옵션 설명을 골라 본 화면과 글 제목

grok -p가 0으로 끝나도 파일이 없을 때: Grok CLI 승인 옵션

예약 작업으로 돌릴 때 제일 곤란한 경우는 완료 응답은 왔는데 작가가 읽을 파일이 없는 상황입니다. grok -p 형태로 자동화하면서 정상 종료만 보고 다음 단계를 시작하면, 이 문제는 한참 뒤에야 드러납니다. 그래서 Grok CLI를 서버의 콘텐츠 작업에 붙일 수 있는지는 Debian 13에서 비대화형 실행이 결과 파일을 정말 남기는지, 그리고 다음 역할까지 작업이 넘어가는지로 판단했습니다. 재현·해결·점검 스크립트의 출력을 근거로 역할별 지시문과 도구 승인 옵션을 같이 손보고, 파일이 빠진 상태를 파이프라인 실패로 바꾸는 기준까지 잡았습니다.

입력 범위와 역할부터 정해 둔 실행 환경

표는 승인 옵션을 비교한 실행 환경과 입력 범위입니다. grok 1.0.52에서 grok-4.7을 썼고, 입력은 Ollama README 앞 60줄을 저장한 파일 하나로 고정했습니다. 같은 자료가 리서처를 거쳐 작가에게 넘어가므로, 결과에서 볼 것은 역할과 역할 사이에 파일이 남았느냐입니다.

항목테스트 환경
OSDebian GNU/Linux 13 (trixie), x86_64
grok 버전grok 1.0.52 (0920c8169e27) [stable]
모델grok-4.7
입력 자료Ollama README 앞 60줄을 저장한 input_source.md
확인일2026-10-15 KST

구조는 Science Based AI의 How I use Grok Bot to go viral on X, LI, and IG (full workflow) (확인일 2026-10-15)에서 가져왔습니다. 영상은 호스티드 Grok Bot에 리서처·총괄·작가 역할을 두고 사람이 각도와 훅을 승인하는 흐름을 보여 주며, 지시문을 Role/Goal/Inputs/Process/Quality bar로 나누라고 안내합니다. 그 구조를 서버의 Grok CLI에 맞게 다시 짰습니다.

Grok CLI(Grok Build) (확인일 2026-10-15)는 헤드리스 모드를 지원합니다. 리서처가 입력 자료에서 명령을 고르고, 작가가 그 결과를 한국어 문장으로 옮기도록 이었습니다. 여기서 승인이 두 종류라는 점을 헷갈리면 안 됩니다. 사람이 콘텐츠 방향을 승인하는 절차와 CLI의 파일 쓰기 도구를 승인하는 절차는 별개이고, 이번에 막힌 것은 뒤쪽, 즉 쓰기 승인과 결과 파일 생성입니다.

입력은 Ollama 저장소 (확인일 2026-10-15)의 README 원문 (확인일 2026-10-15) 앞 60줄로 묶었습니다. 리서처가 다른 자료를 섞지 않도록 범위를 정하고, 작가에게도 brief.md에 있는 사실만 쓰라고 지시합니다. input_source.md는 아래 명령으로 만듭니다.

curl -s https://raw.githubusercontent.com/ollama/ollama/main/README.md | head -60 > input_source.md

종료 코드는 0인데 brief.md가 없다

승인 옵션 없이 리서처만 실행했을 때

grok -p 증상을 다시 일으킨 기록은 지시문을 파일로 넘기는 –prompt-file 방식입니다. 실행 폴더 wa에 input_source.md를, 상위 prompts 폴더에 researcher.md를 둡니다. stdin을 닫고 실행한 뒤 종료 코드, 파일 목록, brief.md 내용을 차례로 봅니다. 재현 스크립트가 쓰는 명령은 다음과 같습니다.

cd wa && grok --cwd "$PWD" -m grok-4.7 --max-turns 10 --prompt-file ../prompts/researcher.md < /dev/null; echo "grok_exit=$?"
ls -la
cat brief.md

승인 옵션을 주지 않으면 응답과 파일 상태가 서로 다른 말을 합니다. grok_exit=0이 찍혔는데 파일 목록에는 input_source.md만 있고, brief.md 조회는 파일 없음 오류로 끝납니다. 명령을 넣겠다는 안내는 쓰기가 끝났다는 뜻이 아니니, 마지막 파일 조회까지 봐야 판단이 섭니다.

$ grok --version
grok 1.0.52 (0920c8169e27) [stable]
$ cd wa && grok --cwd "$PWD" -m grok-4.7 --max-turns 10 --prompt-file ../prompts/researcher.md < /dev/null; echo "grok_exit=$?"
I'll read `input_source.md` and pull one install or run command from it verbatim for `brief.md`.The Linux section has a one-line install command. I'll put that in `brief.md` exactly as it appears.
grok_exit=0
$ ls -la
total 12
drwxr-xr-x 2 box box 4096 Oct 15 23:06 .
drwxr-xr-x 8 box box 4096 Oct 15 23:06 ..
-rw-r--r-- 1 box box 1351 Oct 15 23:06 input_source.md
$ cat brief.md
cat: brief.md: No such file or directory
brief_exists=no

재현 스크립트를 돌린 터미널에도 같은 실패가 그대로 찍혀 있습니다. 종료 값 0과 없는 brief.md, 이 조합이 문제의 전부입니다. 예약 작업이 성공 알림을 보냈어도 작가에게 넘길 입력이 준비됐다고 볼 수 없다는 것이 화면에서 바로 보입니다.

Grok CLI 실행 화면: grok은 0으로 끝나지만 cat brief.md는 파일 없음 오류를 냅니다
2026-10-15 23:07 KST, Debian 13 — grok은 0으로 끝나지만 cat brief.md는 파일 없음 오류를 냅니다.

계획 문장만 남기고 쓰기 도구는 승인 대기에서 끝남

오류 줄은 cat: brief.md: No such file or directory입니다. grok_exit=0인데 파일 목록에 brief.md가 없고, 마지막 확인도 brief_exists=no입니다. 종료 코드만 검사하는 cron 작업이라면 이 상태를 성공으로 넘깁니다. 모델 응답과 프로세스 종료 상태만 믿고 다음 작업을 시작하면 작가에게 넘길 입력이 통째로 사라지는 셈입니다.

“첫 문장만 출력한다”는 증상은 작업 계획을 말해 놓고 파일은 남기지 않는 상태를 가리킵니다. 캡처에는 읽겠다는 안내와 명령을 넣겠다는 안내가 함께 있으니, 출력 문장 수로 장애를 판정할 수는 없습니다. 기준은 약속한 결과 파일이 있느냐입니다. 실행 기록을 보면 읽기 도구는 돌았고, 쓰기 도구는 승인 대기에 걸린 채 비대화형이라 진행되지 못하고 끝난 것으로 해석됩니다. 이 원인 설명은 어디까지나 해당 실행 기록에 근거한 해석입니다.

역할별 지시문을 쓰고 --always-approve로 쓰기를 허용

prompts/researcher.md에 아래 내용을 저장합니다. Role은 맡은 역할, Goal은 골라낼 정보, Inputs는 자료 범위입니다. Process에는 원문 명령을 그대로 고르는 절차를, Quality bar에는 brief.md의 줄 수와 필드 형식을 적었습니다. 이렇게 써 두면 다음 단계가 어느 파일을 읽어야 하는지 헷갈릴 일이 없습니다.

Role: You are the researcher for a Korean tech blog.
Goal: Pick the single most useful fact for Linux users from input_source.md.
Inputs: input_source.md in the current directory. Use no other source.
Process: Read the file. Choose one install or run command that appears in it verbatim. Do not invent anything.
Quality bar: Write brief.md with exactly 3 lines: "topic: ...", "command: <the command copied verbatim>", "source: input_source.md".

prompts/writer.md에는 아래 내용을 넣습니다. 작가는 brief.md가 없으면 멈추고, 있으면 그 안의 명령을 그대로 담은 합니다체 문장을 draft.md에 씁니다. 역할을 나눈 이유는 리서처의 입력 범위와 작가의 표현 범위를 따로 묶어 두기 위해서입니다. 다만 지시문에 파일 이름을 분명히 적는 것만으로는 부족하고, CLI가 쓰기를 할 수 있게 허용하는 일도 같이 해야 합니다.

Role: You are the writer for a Korean tech blog.
Goal: Turn brief.md into a short Korean paragraph.
Inputs: brief.md in the current directory, written by the researcher stage.
Process: Read brief.md. If brief.md does not exist, stop and say so. Use only facts in brief.md.
Quality bar: Write draft.md with 2 Korean sentences in 합니다체 that include the command from brief.md verbatim. No numbers or claims that are not in brief.md.

전용 작업 폴더 wb에 input_source.md를 두고, –always-approve를 넣어 리서처와 작가를 차례로 실행합니다. 해결 스크립트 출력에는 실행 명령과 함께 researcher_exit=0, writer_exit=0이 남습니다. 목록에는 brief.md가 110 bytes, draft.md가 107 bytes로 보이고, 파일을 열면 선택한 설치 명령이 한국어 문장까지 이어져 있습니다. 앞에서 빠졌던 승인 옵션을 넣고 나니 종료 상태와 산출물 내용이 비로소 같은 이야기를 합니다.

$ cd wb && grok --cwd "$PWD" -m grok-4.7 --max-turns 10 --always-approve --prompt-file ../prompts/researcher.md < /dev/null > researcher.log 2>&1; echo "researcher_exit=$?"
researcher_exit=0
$ cat brief.md
topic: Install Ollama on Linux
command: curl -fsSL https://ollama.com/install.sh | sh
source: input_source.md
$ grok --cwd "$PWD" -m grok-4.7 --max-turns 10 --always-approve --prompt-file ../prompts/writer.md < /dev/null > writer.log 2>&1; echo "writer_exit=$?"
writer_exit=0
$ cat draft.md
리눅스에 Ollama를 설치합니다. 명령은 curl -fsSL https://ollama.com/install.sh | sh 입니다.
$ ls -la
total 28
drwxr-xr-x 2 box box 4096 Oct 15 23:07 .
drwxr-xr-x 8 box box 4096 Oct 15 23:07 ..
-rw-r--r-- 1 box box  110 Oct 15 23:07 brief.md
-rw-r--r-- 1 box box  107 Oct 15 23:07 draft.md
-rw-r--r-- 1 box box 1351 Oct 15 23:07 input_source.md
-rw-r--r-- 1 box box  392 Oct 15 23:07 researcher.log
-rw-r--r-- 1 box box  359 Oct 15 23:07 writer.log

Grok CLI 실행 화면: 승인 옵션을 준 두 역할이 종료 값 0으로 brief.md와 draft.md를 만듭니다
2026-10-15 23:07 KST, Debian 13 — 승인 옵션을 준 두 역할이 종료 값 0으로 brief.md와 draft.md를 만듭니다.

캡처에서도 리서처가 topic, command, source로 된 brief.md를 만들고, 작가가 그 명령을 한국어 문장에 넣어 draft.md로 저장한 흐름이 보입니다. 단계마다 종료 값 0과 실제 파일 내용이 함께 있으니, 앞선 재현과 달리 산출물이 넘어갔다고 판단할 수 있습니다. 승인 옵션을 넣은 뒤에도 ls -la 확인을 빼지 않은 것은 실행을 허용한 것과 작업이 끝난 것을 따로 검증하기 위해서입니다.

  • –always-approve를 준 실행에서는 리서처와 작가가 필요한 파일을 만들고 다음 단계로 넘어가는 것이 확인됩니다. 역할별 지시문 덕분에 자료 선택과 문장 작성을 나눠서 점검할 수 있습니다.
  • 걸리는 점은 도구 승인 범위입니다. 무엇까지 승인되는지 따로 검토해야 하고, 쓰기 도구만 허용하려는 운영 구성이라면 뒤에 나오는 –allow Write 방식과 견줘 봐야 합니다. 지시문을 아무리 자세히 써도 결과 파일 검사를 대신해 주지는 않습니다.

acceptEdits로는 풀리지 않은 쓰기와 –allow Write 표기

acceptEdits는 이번 쓰기 작업을 풀지 못했다

–permission-mode acceptEdits만 준 기록에서도 brief.md는 생기지 않았고 종료 코드는 정상으로 나왔습니다. 옵션 이름만 보고 이번 파일 생성 문제가 풀린다고 짐작하면 안 됩니다. –allow write, –allow write_file, –allow Edit 같은 다른 표기는 이 글의 출력 블록에 결과가 남아 있지 않으니, 출력에서 파일 생성이 확인된 –allow Write 표기를 글자 그대로 옮겨 씁니다.

아래 pipeline.sh는 –allow Write로 쓰기 도구를 허용하고, 단계가 끝날 때마다 종료 코드와 결과 파일을 함께 봅니다. 파일이 없거나 비어 있으면 실패로 처리하려고 [ ! -s "$2" ] 조건을 넣었습니다. 리서처 단계가 실패하면 작가 단계로 넘어가지 않고, 그 단계의 출력은 별도 로그에 남습니다.

#!/bin/bash
# cron 용 2단계 파이프라인: 각 단계 뒤 결과 파일을 확인하고, 없으면 실패로 종료한다.
set -u
export PATH=$HOME/.local/bin:$PATH
D=$(cd "$(dirname "$0")" && pwd); W=$1; cd "$W" || exit 2
stage(){ # stage <프롬프트> <결과파일>
  grok --cwd "$W" -m grok-4.7 --max-turns 10 --allow Write --prompt-file "$1" < /dev/null > "$2.log" 2>&1
  rc=$?; if [ $rc -ne 0 ] || [ ! -s "$2" ]; then echo "ERROR: stage $(basename "$1") failed (exit=$rc, $2 missing)"; exit 1; fi
  echo "ok: $2 ($(wc -c < "$2") bytes)"
}
stage "$D/prompts/researcher.md" brief.md
stage "$D/prompts/writer.md" draft.md

역할별 지시문은 스크립트 옆 prompts 폴더에 두고, input_source.md를 넣은 전용 작업 폴더의 절대 경로를 인자로 넘깁니다. 점검 스크립트 기록은 acceptEdits를 쓴 경우와 –allow Write로 되살린 경우를 나란히 보여 줍니다. 출력 블록의 sed 명령은 비교를 위해 pipeline.sh의 옵션을 바꿨다가 되돌리는 부분입니다.

$ cd wc1 && grok --cwd "$PWD" -m grok-4.7 --max-turns 10 --permission-mode acceptEdits --prompt-file ../prompts/researcher.md < /dev/null > r.log 2>&1; echo "acceptEdits_exit=$?"; ls; cd ..
acceptEdits_exit=0
input_source.md  r.log
$ sed -i "s/--allow Write/--permission-mode acceptEdits/" pipeline.sh && bash pipeline.sh "$R/wc1"; echo "pipeline_exit=$?"; sed -i "s/--permission-mode acceptEdits/--allow Write/" pipeline.sh
ERROR: stage researcher.md failed (exit=0, brief.md missing)
pipeline_exit=1
$ bash pipeline.sh "$R/wc2"; echo "pipeline_exit=$?"
ok: brief.md (110 bytes)
ok: draft.md (119 bytes)
pipeline_exit=0
$ ls wc2
brief.md  brief.md.log	draft.md  draft.md.log	input_source.md

Grok CLI 실행 화면: brief.md 누락 시 파이프라인은 1, --allow Write 적용 시 0을 반환합니다
2026-10-15 23:08 KST, Debian 13 — brief.md 누락 시 파이프라인은 1, –allow Write 적용 시 0을 반환합니다.

acceptEdits 실행은 acceptEdits_exit=0인데도 결과 파일이 없습니다. 같은 옵션으로 돌린 pipeline.sh는 ERROR: stage researcher.md failed (exit=0, brief.md missing)을 찍고 pipeline_exit=1로 끝납니다. –allow Write를 쓴 실행에서는 brief.md와 draft.md가 생긴 것이 확인되고 pipeline_exit=0이 돌아옵니다. 파일 검사를 하나 넣었을 뿐인데, CLI가 정상 종료한 경우에도 빠진 산출물이 작업 실패로 드러납니다.

cd 하기 전에 지시문 경로를 절대 경로로 고정

처음 만든 pipeline.sh는 cd로 작업 폴더에 들어간 다음 "$(dirname "$0")/prompts" 상대 경로로 지시문을 읽다가 실패했습니다. 아래 오류는 현재 위치를 기준으로 researcher.md를 찾았는데 없어서 지시문을 못 읽었다는 뜻입니다. 이 상태에서는 역할 지시가 아예 전달되지 않으니, 쓰기 승인 옵션을 만지기 전에 경로부터 고쳐야 합니다.

Error: Failed to read './prompts/researcher.md': No such file or directory (os error 2)

스크립트 시작 부분에서 D=$(cd "$(dirname "$0")" && pwd)로 스크립트 위치의 절대 경로를 잡아 두면 해결됩니다. 그 뒤로는 작업 폴더로 옮겨 가도 "$D/prompts/researcher.md"와 "$D/prompts/writer.md"를 씁니다. 승인 옵션을 조정하기 전에 지시문 파일이 실제로 읽히는 경로인지부터 보면, 경로 문제와 쓰기 승인 문제가 섞이지 않습니다.

CLI를 갱신할 때 다시 돌려 볼 것

실행 기준은 출력에 남은 grok 1.0.52이고, 버전을 올릴 때는 승인 옵션과 파일 생성 동작을 함께 다시 봅니다. 운영 설정에 반영할 근거는 하나입니다. acceptEdits 실행은 정상 종료하고도 파일을 남기지 않았고, –allow Write를 쓴 파이프라인은 산출물을 만들었다는 차이입니다. CLI를 갱신하면 기존 옵션 이름이 그대로 통할 거라 여기지 말고, 별도 작업 폴더에서 같은 입력과 지시문으로 파일 생성까지 다시 돌립니다. 허용 규칙을 지시문 경로와 한데 묶어 관리해 두면, 실행 환경이 바뀌었을 때 어느 쪽이 달라졌는지 바로 대조됩니다.

이 작업의 헬스체크도 CLI가 실행되는지만 볼 것이 아니라 리서처와 작가의 결과가 이어지는지까지 보도록 고칩니다. 지시문은 스크립트 위치를 기준으로 고정하고, 산출물은 –cwd로 지정한 작업 폴더에서 검사하도록 경로의 기준을 맞춥니다. 서비스 상태 점검과 콘텐츠 생성 작업을 떼어 놓으면 생성 실패를 서비스 프로세스 장애로 착각하지 않게 됩니다. 파일이 있는지 본 다음에는 원문 명령이 보존됐는지까지 확인해야 이 작업의 목적에 맞는 완료 판단이 됩니다.

stdin을 닫고 산출물을 열어 보는 운영 규칙

비대화형 명령에는 < /dev/null을 붙여 stdin을 닫고, 단계별 작업에는 전용 폴더와 –cwd를 지정합니다. 이 파이프라인은 리서처 결과를 작가가 이어 읽도록 같은 작업 폴더를 넘깁니다. CLI가 완료를 알려도 ls -la로 산출물을 보고, brief.md에서 draft.md로 내용이 이어졌는지도 봅니다. bypassPermissions는 모든 도구를 제한 없이 허용하는 모드라 쓰지 않습니다.

첨부 스크립트가 검사하는 범위도 분명히 해 둡니다. 파일이 비어 있지 않다는 것과 내용이 지시문을 다 만족한다는 것은 다른 이야기입니다. 운영할 때는 전용 작업 폴더에 예전 산출물이 남아 있지 않은지 보고, 리서처가 입력에 있던 명령을 옮겼는지, 작가가 그 명령을 그대로 살렸는지 확인합니다. b와 c의 draft.md 크기가 다른 것은 서로 다른 실행이었기 때문입니다.

정기 작업은 –allow Write와 단계별 파일 검사로

방식실행 결과운영 판단
승인 옵션 없음종료 코드 0, brief.md 없음종료 코드만으로 성공을 판단하지 않습니다.
–always-approvebrief.md와 draft.md 생성단계 연결을 확인하고 승인 범위를 살핍니다.
–permission-mode acceptEditsbrief.md 없음이번 파일 생성 작업의 해결책으로 선택하지 않습니다.
–allow Write와 pipeline.sh파일 생성 성공, 누락 시 실패 종료도구 허용과 산출물 검사를 함께 적용합니다.

역할별 지시문을 이어 파일 생성 흐름부터 확인하려는 경우에는 성공 기록이 있는 –always-approve 구성으로 시작하기를 추천합니다. cron처럼 다음 단계가 결과 파일에 기대는 경우에는 –allow Write와 단계별 산출물 검사를 함께 거는 구성을 추천합니다. acceptEdits만으로 풀리지 않는다면 같은 실행을 되풀이하지 말고, 허용 규칙의 대소문자, 지시문 절대 경로, 작업 폴더를 차례로 봅니다.

점검 스크립트 출력을 근거로 운영 구성으로 고른 조합은 –allow Write, 역할별 지시문 절대 경로, 단계별 파일 검사입니다. –always-approve로 역할 연결이 되는지 먼저 확인하고, 정기 작업에서는 필요한 쓰기 허용과 산출물 조건을 같이 관리하는 쪽이 판단하기 쉬웠습니다. 다시 돌리기 전에는 기존 brief.md와 draft.md를 구별할 수 있게 작업 폴더를 준비해야, 오래된 파일 때문에 성공으로 처리되는 일을 피합니다. 로그는 역할별로 남기고, 다음 단계는 이번 실행의 결과가 준비된 뒤에만 시작합니다.

실시간 서비스에 붙인다면 요청을 받는 부분과 콘텐츠를 생성하는 작업을 나누고, 생성 결과가 준비된 뒤에 건네는 구성을 권합니다. 처리 지연과 동시 작업에 맞춰 사양을 정할 때는 실제 서비스 부하에서 산출물 전달까지 이어지는 흐름을 봐야 합니다. 이번 실패에서 얻은 교훈은 계획 문장이 그럴듯해도 다음 역할이 읽을 파일은 없을 수 있다는 것입니다. 서버에 맡길 때 제가 완료로 치는 시점은 응답이 끝났을 때가 아니라, 고른 원문 명령이 최종 문장까지 살아 있는 것을 확인했을 때입니다.

터미널에서 돌리는 다른 코딩 에이전트와 MCP 서버, 스킬 라이브러리 글은 AI 코딩 에이전트 허브에서 에이전트 실행, 도구 연결, 스킬 순서로 이어서 볼 수 있습니다.

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다