מדריך גרוק CLI בעברית

תיעוד 38

מצב headless וסקריפטים

מצב headless מריץ את Grok באופן לא אינטראקטיבי משורת הפקודה. הוא מקבל פרומפט יחיד, מריץ אותו עם גישה מלאה לכלים, ומחזיר את התוצאה. השתמשו בו כדי להפוך משימות לאוטומטיות, לכתוב סקריפטים לזרימות עבודה, לבנות אינטגרציות, ולנתח פלט באופן תכנותי.


#שימוש בסיסי

העברת פרומפט באופן לא אינטראקטיבי מפעילה את מצב headless. הדרך הנפוצה ביותר היא הדגל -p (קיצור של --single). גם --prompt-json ו---prompt-file מפעילים אותו:

grok -p "Your prompt here"

Grok מעבד את הפרומפט, מריץ כלים נדרשים, ומדפיס את התוצאה ל-stdout. התהליך יוצא כשהתשובה הושלמה.


#אפשרויות שורת פקודה

דגלתיאור
-p, --single <PROMPT>הפרומפט לשליחה (או שימוש ב---prompt-json / --prompt-file)
-m, --model <MODEL>המודל לשימוש (לדוגמה, grok-4.6)
-s, --session-id <ID>יוצר סשן חדש עם UUID זה (שגיאה אם ה-UUID לא תקין או כבר בשימוש תחת תיקיית הסשנים היעד. לא ממשיך סשן, השתמשו ב--r/-c)
--fork-sessionעם -r/-c, מפצל למזהה סשן חדש במקום לצרף לסשן המקורי
-r, --resume <ID_OR_TITLE>ממשיך סשן קיים לפי מזהה, או לפי כותרת עבור התיקייה הנוכחית, בלי התחשבות ברישיות (בלי התאמה מדויקת, אותן מילים שמחוברות במפרידים כלשהם גם מתאימות, כך ש-fix-login-bug מוצא את "Fix login bug". התאמה יחידה ששמה שונה ידנית מנצחת בין כפילויות. כפילויות שנותרות מחזירות שגיאה עם עד עשר מהן, החדשות קודם, עם מזהים וזמני עדכון אחרונים. החמצה מציעה עד חמש כותרות דומות עם המזהים שלהן. ערכים בצורת UUID תמיד הולכים בנתיב המזהה. סקריפטים צריכים להעדיף מזהים)
-c, --continueממשיך את הסשן האחרון בתיקייה הנוכחית
--cwd <PATH>מגדיר תיקיית עבודה
--add-dir <DIR>גם עובד בתיקייה הזו (ניתן לחזור). נתיב יחסי מתחיל מתיקיית העבודה. נדחה אם התיקייה לא מהימנה או שהסוכן עובד רק בתיקיית העבודה שלו. אי אפשר לשלב עם -r/-c: סשן שהמשיכו שומר את התיקיות שאיתן נוצר.
--output-format <FMT>פורמט פלט: plain, json, streaming-json, streaming-messages-json
--include-partial-messagesפולט דלתאות גולמיות של stream_event. משפיע רק על --output-format streaming-messages-json. אחרת מתעלמים (עם אזהרה).
--yoloמאשר אוטומטית את כל הרצות הכלים
--rules <TEXT>כללים מותאמים לפרומפט המערכת
--tools <TOOLS>רשימת היתר של כלים מובנים (מופרדים בפסיקים). כלי מטא של MCP נשארים זמינים אלא אם נדחו.
--disallowed-tools <TOOLS>רשימת חסימה של כלים מובנים להסרה (מופרדים בפסיקים). תומך ברשומות Agent.
--max-turns <N>מספר מרבי של תורות סוכן לפני עצירה. רק ב-headless.
--reasoning-effort / --effort <LEVEL>מאמץ חשיבה למודלי חשיבה. רמות קנוניות: none, minimal, low, medium, high, xhigh, max (כל אחת שכבה נפרדת. מודל מקבל רק את הרמות שהתפריט שלו מפרסם). מקבל גם מזהי אפשרויות תפריט לפי מודל (לדוגמה deep שממופה לערך wire), כמו /effort. עובד ב-TUI וב-headless.
--permission-mode <MODE>מצב הרשאות. bypassPermissions מפעיל אישור תמידי (ראו הרשאות ובטיחות). plan מתחיל את הסשן במצב תוכנית. לדחייה כברירת מחדל השתמשו ב-defaultMode בקובץ .claude/settings.json.
--allow <RULE>כלל הרשאת היתר עם תבניות glob (ניתן לחזור). עובד ב-TUI וב-headless.
--deny <RULE>כלל הרשאת דחייה עם תבניות glob (ניתן לחזור). עובד ב-TUI וב-headless.
--prompt-json <JSON>פרומפט כבלוקי תוכן JSON
--prompt-file <PATH>פרומפט מקובץ
--verbatimשולח את הפרומפט בדיוק כפי שניתן
--no-auto-updateמבטל בדיקות עדכון לסשן זה
--sandbox <PROFILE>פרופיל sandbox לגישה למערכת קבצים ולרשת

הערה: --max-turns ו---agents הם דגלים רק ל-headless. אם משתמשים בהם ב-TUI האינטראקטיבי, מודפסת אזהרה והדגל מתעלם. --tools, --disallowed-tools, --reasoning-effort/--effort, --permission-mode, --allow ו---deny עובדים בשני המצבים. לדגלים נוספים (סוכנים ו-worktrees), ראו דגלי headless נוספים.

#סינון כלים

השתמשו ב---tools כדי להגביל את הסוכן לקבוצת כלים מפורשת (רשימת היתר), או ב---disallowed-tools כדי להסיר כלים מסוימים מקבוצת ברירת המחדל (רשימת חסימה). שניהם מקבלים שמות כלים מופרדים בפסיקים.

שמות הכלים הם מזהי כלים פנימיים (לדוגמה כלי המעטפת הוא run_terminal_cmd, לא bash). בנתיב ה-daemon, גם השמות שהנתיב הזה מציג עובדים: Shell, Await, StrReplace, EditNotebook, Delete, ReadLints, SwitchMode, AskQuestion, CreatePlan, CallMcpTool, GetMcpTools, FetchMcpResource, ListMcpResources, GenerateImage, GenerateVideo, CreateGoal, UpdateGoal ו-XSearch. StrReplace ו-EditNotebook שניהם שמות של כלי העריכה האחד, כך ש---tools EditNotebook מתיר עריכות לכל קובץ.

# Only allow read-only tools
grok -p "Explain this codebase" --tools "read_file,grep,list_dir"

# Remove web access and file editing
grok -p "Review this code" --disallowed-tools "web_search,web_fetch,write,search_replace"

# Remove shell access
grok -p "Review this code" --disallowed-tools "run_terminal_cmd"

רשומת --disallowed-tools יכולה להיות גם השם שמוצג למודל, וזה מה שתמליל מציג. חמישה כלים מוצעים תחת שם שונה מהמזהה שלהם: run_terminal_cmd בתור run_terminal_command, task בתור spawn_subagent, get_task_output בתור get_command_or_subagent_output, wait_tasks בתור wait_commands_or_subagents, ו-kill_task בתור kill_command_or_subagent. כל אחד משני האיותים מסיר את הכלי בנתיב ה-shell. בנתיב ה-daemon, רשומה לא מסירה כלום, עם אזהרה, כשלכלים שהיא מציינת אין מקבילה ב-daemon, כמו get_task_output, wait_tasks, lsp, enter_plan_mode, monitor, וכלי scheduler_*. גם workflow לא מסיר שם כלום, עם אותה אזהרה: למודל אין כלי workflow בנתיב הזה, והוא מתחיל workflows עם Execute. כיבוי workflows ([workflows] enabled = false או GROK_WORKFLOWS=0) מסיר את Execute. רשומת --disallowed-tools שמציינת סוג תת-סוכן כמו Agent(explore) לא מסירה כלום ומזהירה גם כן, אלא אם הרשימה כוללת גם Agent או Task בלבד, שכבר מסירים את כלי המשימה. run_terminal_cmd ו-task מסירים את כלי ה-shell ואת כלי המשימה של ה-daemon. StrReplace, EditNotebook או search_replace מסירים את כלי העריכה, ו-Delete הולך איתם. write מסיר את Write לבד. במקום שבו ה-bundle בנתיב ה-daemon לא יכול לציין את Write לבד, write מסיר את כל כלי העריכה ואת Delete איתו, כפי ש-grok -p מזהיר. read_file ו-hashline_read, grep ו-hashline_grep, ו-search_replace ו-hashline_edit מציינים את אותו כלי קבצים, לפי ערכת כלי הקבצים שפעילה. בנתיב ה-daemon image_edit מציין את אותו כלי תמונה כמו image_gen. CreateGoal יוצא כש-UpdateGoal יוצא, ו-/goal הולך איתו. UpdateGoal שנשמר נשאר, כך ש---tools CreateGoal צריך גם UpdateGoal. הנתיב הזה גם מציג את Read, Grep, Glob, TodoWrite, WebSearch, WebFetch, ואת כלי העריכה בתור Write. רשומה של אחד מהשמות האלה לא מסירה כלום ומזהירה. השתמשו ב-StrReplace לכלי העריכה. Await ו-kill_command_or_subagent מוסרים ברגע שכלי ה-shell וכלי המשימה שניהם הוסרו. רשומה שלא מציינת שום כלי לא מסירה כלום, ו-grok -p מדפיס עבורה אזהרה ל-stderr. רשומת --tools שלא מציינת שום כלי משאירה את שאר הכלים זמינים. גם הרשומה הזו מזהירה. רשומת --tools שמציינת כלי מחוץ לערכות הכלים המובנות לא מעניקה כלום אלא אם הסוכן מוסיף אותו, ובנתיב ה-shell היא מזהירה. ה-TUI מדפיס את האזהרות האלה ל-stderr לפני שהוא נפתח, ובאנר הפתיחה שלו גם מציג אותן מעל כל אזהרת הפעלה אחרת. ב-TUI רשימה שהוגדרה שומרת את הסשן מחוץ ל-leader המשותף. בנתיב ה-daemon אי אפשר לפתוח סשן במחשב אחר כל עוד אחת מהרשימות מוגדרת, ואי אפשר אז להתחיל או להמשיך workflow. כשהמחשב הזה הוא יעד Remote Control (/remote), תור שמכשיר שולט מתחיל כאן עוקב אחרי --tools ו---disallowed-tools של חלון grok שה-worker שלו מחזיק את החיבור. בנתיב ה-daemon רשומת --tools שמציינת סוג תת-סוכן, כמו Agent(explore), עוצרת את grok -p ואת ה-TUI עם שגיאה.

--disallowed-tools תומך גם ברשומות Agent מיוחדות כדי לשלוט ביצירת תת-סוכנים:

רשומההשפעה
Agentחוסם את כל יצירת תת-הסוכנים
Agent(explore)חוסם רק את סוג תת-הסוכן explore
Agent(explore, plan)חוסם כמה סוגים מסוימים
# Prevent the agent from spawning any subagents
grok -p "Fix this bug" --disallowed-tools "Agent"

# Block only the explore subagent
grok -p "Refactor this module" --disallowed-tools "Agent(explore)"

--tools שומר את מדיניות ההזרקה של פרופיל הסוכן שנבחר: פרופילי stock מזריקים כלים אופציונליים מופעלים לפני החלת רשימת ההיתר, בעוד פרופילים curated נשארים מחמירים. ערכת הכלים הסופית שומרת את הכלים שנתבקשו ועוד כלי מטא של MCP שפועלים תמיד. כששני הדגלים נוכחים, --disallowed-tools מנצח.

#כללי הרשאות (--allow / --deny)

כללי הרשאות שולטים אם הפעלות כלים מסוימות מאושרות אוטומטית, נדחות, או דורשות אישור משתמש. בניגוד ל---disallowed-tools (שמסיר כלים לגמרי), כללי הרשאות משאירים את הכלים זמינים אבל שמים שער על ההרצה שלהם.

הכללים משתמשים בתחביר ToolPrefix(glob_pattern):

קידומתבמה זה שולט
Bash(...)הרצת פקודות מעטפת
Edit(...)עריכת קבצים (glob של נתיב)
Write(...)כתיבת קבצים (glob של נתיב)
Read(...)קריאת קבצים (glob של נתיב)
Grep(...)פעולות חיפוש (glob של נתיב)
WebFetch(...)שליפת URL (glob או domain:host)
MCPTool(...)הפעלות כלי MCP

לכללי נתיב (Read, Edit, Write, Grep), * הוא תו כללי ברמה אחת ו-** הוא רקורסיבי. לכללי Bash, * מתאים לכל תווים כולל רווחים. קידומת חשופה בלי סוגריים מתאימה לכל ההפעלות מהסוג הזה, ו-Bash(cmd:*) שקול להתאמת קידומת על cmd. ראו 22-permissions-and-safety.md לסמנטיקת ההתאמה המלאה.

# Deny shell commands matching "rm*"
grok -p "Clean up this project" --deny "Bash(rm*)"

# Allow npm commands, deny sudo
grok -p "Set up the project" --allow "Bash(npm*)" --deny "Bash(sudo*)"

# Allow all bash commands (auto-approve without prompting)
grok -p "Build the project" --allow "Bash"

אפשר לחזור על --allow ו---deny. כללי דחייה גוברים על כללי היתר. ערך אחד יכול גם להחזיק כמה כללים, מופרדים בפסיקים או ברווח אחרי סוגר סוגר: --deny "Bash(rm *) Edit(.env)". כתבו ) בתוך תבנית בתור \) כדי שהוא לא ייקרא כסוף הכלל.

--allowedTools ו---allowed-tools הם כינויים של --allow. --disallowedTools הוא כינוי של --deny. --disallowed-tools מסיר כלים מהרשימה המוצעת (ראו סינון כלים).


#פורמטי פלט

מצב headless תומך בארבעה פורמטי פלט, שנבחרים עם --output-format.

#plain (ברירת מחדל)

טקסט קריא לאדם, מתאים להצגה ישירה או להעברה בצינור:

Here's a summary of the codebase...

#json

אובייקט JSON יחיד שנפלט אחרי שהתשובה הושלמה: טקסט התשובה, סיבת עצירה, מזהה סשן, מזהה בקשה, והתיקייה שבה רץ הסשן (ועוד thought כשיש חשיבה). כשהפרומפט הגיע למודל, אותו אובייקט נושא גם שדות הוצאה (usage, num_turns, modelUsage, עלות). stopReason הוא אסימון snake_case של ACP/Messages (end_turn, max_tokens, …).

{
  "text": "Here's a summary of the codebase...",
  "stopReason": "end_turn",
  "sessionId": "abc123",
  "requestId": "xyz789",
  "cwd": "/repo",
  "num_turns": 7,
  "usage": {
    "input_tokens": 7210,
    "cache_read_input_tokens": 41000,
    "cache_creation_input_tokens": 0,
    "output_tokens": 1893,
    "reasoning_tokens": 412,
    "total_tokens": 50103
  },
  "modelUsage": {
    "grok-4.6": {
      "inputTokens": 7210,
      "outputTokens": 1893,
      "cacheReadInputTokens": 41000,
      "modelCalls": 7,
      "costUSD": 0.01268905
    }
  },
  "total_cost_usd": 0.01268905,
  "total_cost_usd_ticks": 126890500
}

הערות שימוש:

  • usage מסכם טוקנים לפרומפט, כולל, בנתיב ה-shell, תת-סוכנים שסיימו לפני סוף התור (גם תחת מפתחות modelUsage משלהם). דחיסה וקריאות מודל צד אחרות לא נכללות.
  • שדות ההוצאה מכסים כל תור שהריצה עשתה: של הפרומפט וכל תור מאוחר יותר בסשן, כמו תור wake או תור goal. הם מצטברים כמו שני התורות של תוכנית שנשמרה (ראו תוכניות שנשמרו). בנתיב ה-daemon, ההוצאה הסוגרת מגדירה usage_is_incomplete ומשמיטה את העלות כשהיא עלולה לפספס קריאת מודל: תור מאוחר יותר הופסק או נכשל, או הסתיים לפני שהשימוש שלו הגיע לריצה. יציאה עצרה תור שהתחיל, או לא יכלה לעצור את העבודה אחרי אות או בלי ש-wait נענה. או ש-goal עדיין רץ ביציאה. בנתיב ה-shell, תור wake שעדיין רץ ביציאה נשאר בחוץ בלי הדגל הזה. בכל אחד מהנתיבים, חיבור שנסגר מגדיר את זה גם כן.
  • מדיניות שדות טוקנים (תוצאת headless / end / הוצאת שגיאה):
    • usage.input_tokens ו-modelUsage.*.inputTokens הם רק לא מהמטמון.
    • cache_read_input_tokens / cacheReadInputTokens הם פגיעות מטמון.
    • total_tokens הוא קלט מלא + פלט (כולל את שני דליי המטמון): total_tokens = input_tokens + cache_read_input_tokens + cache_creation_input_tokens + output_tokens.
    • _meta.usage.inputTokens של ACP (PromptUsage) עדיין הסכום המלא של הפרומפט. רק המקרן של headless מחסיר מטמון. העדיפו שדות headless לאוטומציה של הוצאה.
  • num_turns סופר סבבי מודל של הסוכן הראשי שנרשמו בפנקס הפרומפט (סבבי לולאת כלים שדיווחו שימוש). קריאות דגימה של תת-סוכן לא מגדילות אותו. ספירות קריאות לפי מודל (כולל תת-סוכנים) נשארות ב-modelUsage.*.modelCalls. זו אותה משפחת מונים כמו --max-turns, בלי הבטחה לשוויון מדויק כשסבבים חסרי שימוש או נתקלים בשערים.
  • total_cost_usd מופיע רק כשהשרת דיווח עלות מלאה. היעדר פירושו שלא דווח או לא שלם, אף פעם לא בחינם. עלות מוחתמת היום לתעבורת מפתח API. נתיבי pool/OAuth לעתים קרובות משמיטים אותה עד שהשרת מחתים עלות. כשחלק מהקריאות חסרו עלות, cost_is_partial הוא true וכל מספרי העלות הצפים מושמטים (total_cost_usd וכל modelUsage.*.costUSD) כדי שצרכנים לא יוכלו לסכם שורות מודל לחשבון מלא מזויף.
  • total_cost_usd_ticks הוא אותו ערך בטיקים שלמים מדויקים (1 USD = 10^10 טיקים) ומופיע באותם תנאים. השתמשו בו להתאמת חיוב: סיכום טיקים לפי הפעלה תואם בדיוק לייצוא השימוש של השרת, דבר שדולרים צפים לא יכולים להבטיח.
  • כשלא היה אפשר להחיל שימוש של תת-סוכן, שימוש של תת-סוכן מקונן היה לא שלם, או שפקיעת הניקוז בנתיב ההצלחה חלה (עד 120 שניות במשימת התור), usage_is_incomplete הוא true ומספרי עלות צפים מושמטים באותו אופן (סכומי טוקנים עלולים לספור תת-סוכנים בחסר). ביטול מצלם בלי הניקוז הארוך הזה ומסמן לא שלם בזמן שתת-סוכנים עדיין חיים. לא שלם בלי טוקנים שנרשמו פולט רק usage_is_incomplete (בלי אובייקט usage אפס).
  • פרומפט שמעולם לא הגיע למודל לא מוסיף הוצאה. השדות מושמטים אלא אם תור אחר או סיבה מהאמור למעלה מגדירים אותם.

השדה sessionId שימושי להמשך השיחה אחר כך.

cwd הוא התיקייה שבה רץ הסשן. עם --worktree NAME, הוא בתוך ה-worktree החדש. כשקיים worktree בשם NAME, Grok יוצא עם שגיאה שמציינת את התיקייה שלו ולא יוצר כלום. NAME שהתיקייה שלו נמחקה ידנית משמש שוב, אלא אם git עדיין מחזיק את הרישום שלו. השגיאה אז אומרת איך לשחרר אותו. במאגר jj, NAME תפוס עדיין הופך ל-NAME-2, NAME-3, וכן הלאה.

בכישלון, Grok פולט אובייקט שגיאה (יציאת תהליך שונה מאפס). כשלונות ברמת הפרומפט יכולים גם לכלול שדות הוצאה קפואים כשנרשם שימוש:

{"type":"error","message":"Couldn't start session: ..."}

אחרי שהסשן התחיל, אובייקט השגיאה נושא גם cwd.

#streaming-json

JSON מופרד בשורות חדשות, אובייקט אחד עם תגית type בכל שורה, נגזר מעדכוני סשן ACP של הסוכן. שמות שדות עלה (toolCallId, kind, rawInput, rawOutput) עוקבים אחרי ACP. toolName ושורה usage הן תוספות של xAI. צורכים את זה על ידי מעבר על type.

{"type":"thought","data":"Analyzing the directory structure..."}
{"type":"tool_call","toolCallId":"call_1","title":"Read","kind":"read","status":"in_progress","toolName":"read_file","rawInput":{"path":"src/main.rs"},"content":[],"locations":[]}
{"type":"tool_call_update","toolCallId":"call_1","status":"completed","content":[],"rawOutput":{"lines":42},"locations":[]}
{"type":"text","data":"Here's a summary"}
{"type":"usage","messageId":"resp_1","stopReason":"end_turn","usage":{"input_tokens":812,"output_tokens":45,"cache_read_input_tokens":0,"cache_creation_input_tokens":0,"reasoning_tokens":0},"signature":"..."}
{"type":"end","stopReason":"end_turn","sessionId":"abc123","requestId":"xyz789","cwd":"/repo","usage":{...},"num_turns":7,"modelUsage":{...}}

סוגי אירועים:

TypeDescription
textמקטע מטקסט התשובה של הסוכן
thoughtנימוק פנימי (טוקני חשיבה)
tool_callקריאת כלי שהסוכן התחיל (toolCallId, toolName, kind, status, rawInput, content, locations)
tool_call_updateהתקדמות או תוצאה לקריאת כלי (status, rawOutput, content, locations)
usageגבול לכל תשובה (messageId, stopReason, usage, signature), אחד לכל תשובת מודל. במסלול הדמון, אחד לכל תור, כולל תורות של תת סוכן, עם usage הכולל של אותו תור בלבד
planהתוכנית הנוכחית של הסוכן (entries)
available_commandsרשימות כלים ופקודות סלאש (tools, commands)
endהאירוע הסופי עם תיקיית הסשן, מטא נתונים, ושדות הוצאה כשהם זמינים
errorאירעה שגיאה (נושא message, את תיקיית הסשן אחרי שהסשן התחיל, ושדות הוצאה אם יש)

end הוא האירוע האחרון, או error כשההרצה נכשלת, גם כש SIGINT או SIGTERM עוצרים את ההרצה אחרי שהפרומפט שלה נשלח (ראו Interrupted Headless Runs). שדות ההוצאה ב end תואמים לצורת אובייקט ה json (input_tokens לא במטמון ב snake_case, מספרים עשרוניים בטוחים לעלות). end.stopReason הוא סיבת עצירת התור ב snake_case (end_turn, max_tokens, max_turn_requests, refusal, cancelled). הסיבה המילולית לכל תשובה מהספק (למשל tool_use, pause_turn) נמצאת ב stopReason של שורת usage. message_id/stopReason/signature לכל תשובה מאוכלסים בבקאנד של Messages API. בקאנדים אחרים מדווחים את מה שהם נושאים.

ההוצאה של end כבר מסכמת כל תור שההרצה ביצעה, אז אל תוסיפו אליה את שורות usage. ל text של תור מאוחר יותר, כמו תשובה של תור התעוררות, אין מעבר פסקה משלו, ושורה usage לא מסמנת איפה הוא מתחיל: תורות של תת סוכן שולחים גם שורות usage, ורק end של מסלול המעטפת סופר אותן.

גרוק עשוי גם לפלוט אירועי max_turns_reached ו auto_compact_*. התייחסו לרשימה כלא ממצה ועברו על type.

#streaming-messages-json

JSON מופרד בשורות חדשות בפורמט החוט stream-json של Messages API. המשטח שנושא נתונים תואם במדויק לצורת Messages. זה כולל גופי הודעות assistant/user, usage, tool_use/tool_result, חיפוש ווב מוטמע, stop_reason, ומסגור האירוע --include-partial-messages. צרכן שבונה מחדש הודעות, קורא הוצאה, או מזהה שגיאות עובד בלי שינויים.

שורות system/init ושורה סופית result נושאות מטא נתונים. גרוק פולט את השדות שיש לו עבורם נתונים אמיתיים ומשמיט שדות שהם placeholder טהור שאי אפשר למלא, במקום למלא אותם באפס. כתוצאה, שתי השורות האלה עשויות לא לעבור אימות סכמה מחמיר של init/result. השדות הבודדים מפורטים למטה. קראו את הערות הנאמנות לפני שמתייחסים לשדה כלשהו כסמכותי. לזרם xAI מקורי נקי בלי צורת placeholder, השתמשו ב streaming-json.

הזרם נפתח בשורת system/init, ואז הודעות assistant ש message.content[] שלהן מחזיק בלוקי text, thinking, ו tool_use, הודעות user שנושאות בלוקי tool_result, ו result סופי:

{"type":"system","subtype":"init","session_id":"abc123","apiKeySource":"user","model":"grok-4.6","cwd":"/repo","permissionMode":"default","tools":["read_file","bash"],"slash_commands":["review"],"mcp_servers":[{"name":"linear","status":"connected"}],"skills":[],"uuid":"..."}
{"type":"assistant","message":{"id":"msg_0","type":"message","role":"assistant","model":"grok-4.6","content":[{"type":"text","text":"Let me read the file."},{"type":"tool_use","id":"call_1","name":"read_file","input":{"path":"src/main.rs"}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{...}},"parent_tool_use_id":null,"session_id":"abc123","uuid":"..."}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"call_1","content":"fn main() {}","is_error":false}]},"parent_tool_use_id":null,"session_id":"abc123","uuid":"..."}
{"type":"result","subtype":"success","is_error":false,"duration_ms":0,"duration_api_ms":0,"num_turns":7,"result":"Here's a summary...","stop_reason":"end_turn","total_cost_usd":0.0127,"usage":{"input_tokens":812,"output_tokens":210,"cache_read_input_tokens":0,"cache_creation_input_tokens":0,"server_tool_use":{"web_search_requests":0}},"modelUsage":{},"session_id":"abc123","uuid":"..."}

סוגי הודעות:

TypeDescription
systemהקדמת סשן (subtype: "init") עם מודל, cwd, מצב הרשאה, כלים, פקודות סלאש, ושרתי MCP. subtype: "compact_boundary" מסמן דחיסה אוטומטית
assistantהודעת מודל. message.content[] מחזיק text/thinking/tool_use, ובנוסף server_tool_use/web_search_tool_result לחיפוש ווב מוטמע של הבקאנד
userתוצאות כלים, כבלוקי tool_result בתוך message.content[]
resultהודעה סופית עם הטקסט הסופי, סיבת עצירה, ושדות הוצאה

הודעות assistant ו user נושאות session_id, uuid, ו parent_tool_use_id (null לשיחה הראשית). שורות system/init ו result הסופי נושאות session_id ו uuid אבל בלי parent_tool_use_id.

ה uuid בכל שורה נוצר מחדש לכל שורה שנפלטת. הוא לא מזהה ספק, הודעה, או אירוע, ולא מפתח מתאם. הוא לא תואם ל message.id של הספק (הערך הזה נוסע ב assistant.message.id). הוא ייחודי לכל שורה, גם לשורות שמתארות את אותה הודעה, והוא לא נושא זהות בין שורות או בין הרצות. אל תשתמשו בו למתאם או להסרת כפילויות.

מקטעי טקסט ונימוק מקובצים להודעת assistant אחת לכל תשובת מודל. בלוקי tool_result מקבילים של תשובה מקובצים להודעת user אחת. result.result הוא טקסט הודעת ה assistant הסופית. תשובת מודל שלא מייצרת בלוקי תוכן לא פולטת שורת assistant במצב ברירת המחדל. רק --include-partial-messages חושף תשובה כזו, כמעטפת ריקה message_start … message_stop.

ב init, skills חי. הוא מפרט את שמות הכישורים שהמשתמש יכול להפעיל בסשן, תת קבוצה של slash_commands שמקורה בפקודות שהסשן מפרסם, או [] כשהסשן לא מציג כישורים. שורת init נפלטת פעם אחת, נדחית עד שורת הפלט הראשונה כדי שתתפוס את tools, slash_commands, ו skills שהסשן מפרסם. סכמת Messages לא מגדירה init שני, אז רשימת פקודות שמשתנה אחרי שהסטרימינג מתחיל לא מפורסמת מחדש.

שאר שדות init נושאים נתונים אמיתיים:

  • apiKeySource הוא user לאימות מפתח API ו oauth אחרת. גרוק לא מבדיל בין מקורות הסכמה project, org, ו temporary.
  • permissionMode הוא מצב ה headless האפקטיבי שממופה ל enum של Messages: הערך של --permission-mode, או bypassPermissions תחת --yolo, אחרת default. מצבים של גרוק בלבד כמו auto מתכווצים ל default.
  • mcp_servers[].status הוא צילום אחד של x.ai/mcp/list, שנפלט רק ל streaming-messages-json: connected, failed, needs-auth, pending, או disabled. שרתים שעדיין ב handshake הם pending. disabled נחתם רק אחרי שהסשן מדווח sessionMcpResolved. שורת רשימה שלא נפתרה היא pending גם כש enabled עדיין false. הצילום לא מחכה לחסד ההפעלה Blocking. החסד הזה עדיין חל על ערכת הכלים של הפרומפט. פורמטי פלט אחרים משמיטים את המערך ולא קוראים ל x.ai/mcp/list.

גרוק משמיט את שדות init שהם placeholder טהור בסכמה ואין לו נתונים עבורם, במקום לפלוט ערכי דמה: claude_code_version, output_style, ו plugins.

result כולל duration_ms, duration_api_ms, num_turns, stop_reason, total_cost_usd, usage (צורת message.usage של Messages API), ו modelUsage. הוא כולל גם errors[] בתתי סוגי השגיאה. גרוק משמיט את permission_denials של הסכמה, שתמיד ריק, כי הוא לא אוסף סירובי הרשאה. structured_output (עם --json-schema) הוא snake_case, בהתאם לסכמה.

model מופיע ב init ובכל מסגרת assistant. זה מזהה המודל האמיתי כשהוא ידוע, והמילולי "unknown" רק כשאף מודל לא ידוע בזמן הפליטה.

stop_sequence של מסגרת ה assistant מחובר מקצה לקצה. הוא נושא את רצף העצירה התואם של הספק כשהמודל עצר על רצף מוגדר (stop_reason: "stop_sequence"), והוא null בכל סיבת עצירה אחרת ובכל בקאנד אחר. במסגור --include-partial-messages, הרצף התואם נוסע גם במסגרת assistant שנשטפה וגם ב message_delta.stop_sequence החלקי, כך שבנייה חלקית מחדש תואמת למסגרת. רק message_start.stop_sequence החלקי נשאר null, כי הרצף התואם לא ידוע בפתיחת ההודעה.

תתי סוגי השגיאה שנפלטים הם error_max_turns, error_during_execution, ו error_max_structured_output_retries. תת הסוג error_max_budget_usd של הסכמה אף פעם לא נפלט, כי לגרוק אין תכונת תקציב. הרצה ש SIGINT או SIGTERM עוצרים אחרי שהפרומפט שלה נשלח מסתיימת ב result מתת סוג error_during_execution, עם stop_reason cancelled ו errors ["cancelled"], או, אחרי פרומפט שנכשל, בתוצאת השגיאה של אותו פרומפט. תוצאה אחרת שהוכרעה לפני האות, כמו error_max_turns או תור שנעצר בגלל refusal או max_tokens, שומרת את ה result שלה (ראו Interrupted Headless Runs).

result.usage מדווח את צורת message.usage של Messages עם שלושת דליי הטוקנים זרים זה לזה: input_tokens (לא במטמון), cache_read_input_tokens, ו cache_creation_input_tokens. גרוק גוזר אותם מפנקס המצטבר של כל תור שההרצה ביצעה, כמו ש end עושה, ומעצב אותם מחדש לדליים האלה. יצירת מטמון של תת סוכן כלולה ב cache_creation_input_tokens. הפנקס המצטבר עוקב אחריה כדלי משלה, אז היא כבר לא מקופלת לתוך input_tokens.

result.usage תמיד פולט דליים מספריים, גם כשחסרים נתונים. זה קורה כשפנקס ה usage של התור לא שלם (אותו תנאי שחושף usage_is_incomplete בפורמט json), או כשאף פנקס מצטבר לא הגיע ל reducer בכלל. כל דלי שגרוק לא יכול לחשב נופל חזרה ל 0, כי לסכמת Messages API אין סמן ל usage לא שלם או חסר. ה reducer רושם אזהרה ל stderr בשני המקרים. קראו usage שכולו אפסים כאן כ "unknown", לא כ "free".

מונה server_tool_use המקונן מאוכלס. web_search_requests הוא מספר חיפושי הווב המוצלחים של הבקאנד שנפלטו בהרצה הזו. חיפושים שנכשלו ופעולות WebSearch שאינן חיפוש כמו open_page לא נכללים, בהתאם ל Messages API, שלא מחייב חיפושים ששגו. חיפוש בקאנד שנכשל עדיין פולט web_search_tool_result בצורת שגיאה (content.type: "web_search_tool_result_error"), אבל לא נספר. error_code שלו הוא placeholder קבוע "unavailable", לא קוד שהועבר מהבקאנד. אין מפתח web_fetch_requests, כי לגרוק אין web_fetch בצד השרת, אז ה placeholder מושמט.

חיפוש ווב של הבקאנד הוא מוטמע. הוא מתקפל לאותה מסגרת assistant כמו הטקסט שמסביב. המסגרת נושאת בלוק server_tool_use (name: "web_search", input.query) ומיד אחריו בלוק web_search_tool_result. tool_use_id של בלוק התוצאה תואם ל server_tool_use.id, ו content שלו הוא מערך פגיעות web_search_result של {type, url, title}. זה תואם לצורת כלי השרת המוטמע של Messages API, במקום לפצל את התשובה בין מסגרות.

חיפוש X ומפרש קוד הם סטייה מתועדת. הם נשארים גנריים, מוצגים כבלוק tool_use של הלקוח ועוד tool_result של user, כי Messages API לא מגדיר סוג בלוק מוטמע עבורם. כל כלי לקוח אחר שומר באותו אופן על הפיצול tool_use/tool_result.

--include-partial-messages פולט את מסגור האירוע הגולמי כדי שצרכן יוכל לבנות מחדש כל הודעה עם צובר הסטרימינג של Messages. המסגור הוא message_start, content_block_start/content_block_delta/content_block_stop, message_delta, ו message_stop. הוא נושא את האירועים המבניים שצובר צריך. הדלתאות גסות יותר מסטרימינג ברמת טוקן של Messages API: קלט כלי מגיע כ input_json_delta יחיד, ו citations_delta אף פעם לא מיוצר (ראו למטה). התוצאה היא שחזור נאמן של כל הודעה, במקום השמעה מחדש טוקן אחרי טוקן.

בבקאנד של Messages API, המסגור נאמן. message_start נושא את message.id האמיתי של הספק ואת usage בצד הקלט. בלוק thinking פולט את signature_delta שלו לפי הסדר, לפני content_block_stop של הבלוק. צד הקלט של message_start.usage מדווח את כל שלושת דליי צד הפרומפט הידועים בפתיחת ההודעה: input_tokens (החלק שלא במטמון), cache_read_input_tokens, ו cache_creation_input_tokens. פגיעת מטמון גלויה אפוא ב message_start, במקום להופיע רק מאוחר יותר ב message_delta/result. output_tokens נזרע שם כ 0 ומסוכם סופית ב message_delta. תשובה שמתחילה אבל לא מייצרת תוכן עדיין פולטת את המעטפת message_start … message_stop בלי בלוקי תוכן.

חלק מהבקאנדים חושפים מטא נתונים לכל תשובה רק בסוף התור. הבקאנדים האלה נופלים חזרה ל message_start.id מסונתז ול usage קלט שנזרע באפס. הם דוחים את signature של הנימוק לשורת assistant הסופית, שהיא הסמכותית במקרה הזה.

קלט של קריאת כלי נפלט כ input_json_delta יחיד שנושא את JSON הארגומנטים המלא, ואחריו content_block_stop. זה לא רצף של מקטעים ברמת טוקן. זו סטייה מכוונת מסטרימינג partial_json המצטבר של Messages API. מסלול קריאת הכלים ACP של גרוק מוסר כל קריאת כלי כאובייקט JSON מאומת אחד אחרי שהארגומנטים מפורשים במלואם, אז דלתא יחידה היא הייצוג המדויק. צרכן שמשרשר partial_json מרכיב מחדש את אותו אובייקט בכל מקרה. input.query של בלוק server_tool_use לחיפוש ווב של הבקאנד נפלט באותו אופן, כ input_json_delta אחד.

citations_delta של Messages API נושא ציטוטים מוטמעים לטווחי טקסט מצוטטים, כמו אלה מחיפוש ווב. הזרם הזה לא מייצר אותו. דלתאות התוכן של Messages של גרוק מוגבלות לטקסט, thinking, signature, ו JSON של קלט כלי, אז אין נתוני ציטוט לחשוף כ citations_delta. כתובות URL של מקורות חיפוש ווב של הבקאנד מדווחות מוטמעות בבלוק web_search_tool_result שהושלם (ראו למעלה), לא כציטוטי טקסט לכל טווח.

הערות נאמנות חלות על כמה שדות.

duration_ms הוא שעון הקיר של ביצוע הפרומפט. duration_api_ms הוא סכום זמן המודל המדווח לכל קריאה. קריאת מודל שלא מדווחת את משך הזמן שלה תורמת 0, אז duration_api_ms יכול לספור בחסר את זמן ה API האמיתי.

num_turns ו total_cost_usd סמכותיים כשהם ידועים. כשהם לא, num_turns נופל חזרה לספירת תשובות המודל שהושלמו בתור הזה, ו total_cost_usd נופל חזרה ל 0. תשובה שהושלמה אבל בלי תוכן לא פולטת שורת assistant, ועדיין נספרת כתור. הוצאה אף פעם לא מדווחת ביתר.

modelUsage נושא את שדות הטוקנים והעלות לכל מודל שגרוק עוקב אחריהם, ועוד webSearchRequests שמיוחסים למודל הפעיל. ה reducer עוקב אחרי ספירת חיפוש ווב גלובלית אחת, במקום לכל מודל, אז כל הספירה נוחתת על המודל הנוכחי או האחרון ושורות אחרות נשארות 0. modelUsage.*.costUSD לכל מודל הוא 0 כשעלות המודל הזה לא ידועה או מוסתרת. זו אותה התנהגות של כשל סגור לאפס כמו total_cost_usd ברמה העליונה. פורמט json משמיט לגמרי מספרים עשרוניים של עלות כשהם חלקיים, אבל הזרם הזה שומר את השדה נוכח ו 0. contextWindow הוא חלון ההקשר הכולל האמיתי של המודל הנוכחי (אותו ערך שגרוק משתמש בו לדחיסה אוטומטית), והוא מופיע רק בשורת המודל הנוכחי. שורות אחרות משמיטות אותו, וכך גם השורה הנוכחית כשהחלון לא ידוע. ל maxOutputTokens אין קטלוג של גרוק, אז המפתח הזה מושמט לגמרי. modelUsage הוא {} כשאין פירוט לכל מודל.

כמו streaming-json, הזרם הזה הוא לקריאה בלבד. אישורי כלים וזרימות דו כיווניות אחרות משתמשים בממשק ACP (grok agent).

#ניהול סשנים במצב headless

כברירת מחדל, כל הפעלה של grok -p יוצרת סשן חדש. כדי לשמור הקשר בין קריאות, השתמשו בדגלי סשן.

#סשנים עם שם (-s)

כדי לשאת הקשר בין קריאות headless, השתמשו ב--r/--resume או ב--c/--continue. השתמשו ב--s/--session-id רק עבור סשן חדש עם UUID (שגיאה אם זה לא UUID או אם הוא כבר בשימוש תחת תיקיית היעד). התנהגות ה-upsert/resume הנסתרת הישנה של -s אינה קיימת עוד. השתמשו ב--r/-c כדי להמשיך. עם -r/-c, -s דורש --fork-session:

# Start a headless session and capture its ID
grok -p "Review the changes in this PR" --output-format json | jq -r '.sessionId'

# Continue in the same session
grok -p "Now check for security issues" --resume "<id>"

# Optional: create with a client-chosen UUID (must not already exist)
grok -p "hello" --session-id "$(uuidgen | tr '[:upper:]' '[:lower:]')" --output-format json

הערה: -s/--session-id יוצר סשן חדש בלבד (UUID תקין, שגיאה אם כבר בשימוש). השתמשו ב--r כדי לחדש.

#חידוש (-r)

דגל -r/--resume מחדש סשן מסוים לפי מזהה, או לפי כותרת עבור התיקייה הנוכחית כאשר הערך אינו מזהה, תוך התעלמות מרישיות האותיות (בלי התאמה מדויקת, אותן מילים שמחוברות על ידי מפרידים כלשהם גם מתאימות, כך ש-fix-login-bug מוצא את "Fix login bug". התאמה יחידה ששמה שונה ידנית גוברת בין כפילויות. כפילויות שנותרות מחזירות שגיאה עם עד עשר מהן, החדשות קודם, עם מזהים וזמני עדכון אחרונים. החמצה מציעה עד חמש כותרות דומות עם המזהים שלהן. ערכים בצורת UUID תמיד הולכים בנתיב המזהה, ולכן סקריפטים צריכים להעדיף מזהים). מתקבלת שגיאה אם הסשן אינו קיים:

# Get the session ID from a previous JSON response
grok -p "Remember: the secret number is 42" --output-format json
# Output includes "sessionId": "abc123"

# Resume that exact session
grok -p "What's the secret number?" --resume abc123

#המשך (-c)

דגל -c/--continue ממשיך את הסשן האחרון בתיקיית העבודה הנוכחית:

grok -p "Continue where we left off" -c

#חילוץ מזהי סשן

השתמשו ב---output-format json ונתחו את השדה sessionId:

grok -p "Hello" --output-format json | jq -r '.sessionId'

#צינורות קלט ופלט

מצב headless עובד באופן טבעי עם צינורות Unix והפניה.

#פלט סטנדרטי

# Pipe output to a file
grok -p "Generate a README" > README.md

# Parse JSON output with jq
grok -p "List files" --output-format json | jq -r '.text'

#קלט סטנדרטי

מצב headless אינו קורא stdin מצינור אל תוך הפרומפט. העבירו תוכן חיצוני דרך החלפת פקודה או --prompt-file:

# Include git diff as context via command substitution
grok -p "Write a concise commit message for these changes:

$(git diff --staged)"

# Or read the prompt from a file
grok --prompt-file ./prompt.txt

#דוגמאות שילוב CI/CD

#סקירת קוד אוטומטית

grok -p "Review changes for bugs and security issues." \
  --output-format json --yolo | jq -r '.text' > review.md

#הוק Pre-Commit

grok -p "Review staged changes for obvious bugs. Reply OK if fine, or list issues." \
  --yolo --output-format json | jq -r '.text' | grep -q "^OK" || exit 1

#עיבוד באצווה

for file in src/*.js; do
  grok -p "Migrate $file from CommonJS to ES modules." --yolo
done

#דפוסי סקריפטים

#מעטפת Python

אפשר לעטוף את מצב ה-headless של Grok כ-API להשלמת צ'אט תואם OpenAI:

import asyncio
import json
import os

class GrokChat:
    """Simple OpenAI-compatible wrapper using headless mode."""

    def __init__(self, cwd="."):
        self.cwd = cwd
        self.env = {**os.environ}

    def _build_cmd(self, prompt, model, stream):
        return ["grok", "-p", prompt, "-m", model, "--cwd", self.cwd,
                "--output-format", "streaming-json" if stream else "json",
                "--yolo"]

    async def create(self, messages, model="grok-4.6", stream=False):
        prompt = messages[-1]["content"] if len(messages) == 1 else "\n".join(
            f"{m['role']}: {m['content']}" for m in messages
        )
        cmd = self._build_cmd(prompt, model, stream)

        if stream:
            return self._stream(cmd)

        proc = await asyncio.create_subprocess_exec(
            *cmd, env=self.env, stdout=asyncio.subprocess.PIPE
        )
        stdout, _ = await proc.communicate()
        data = json.loads(stdout.decode()) if stdout else {"text": ""}
        return {
            "choices": [{
                "message": {"role": "assistant", "content": data.get("text", "")},
                "finish_reason": "stop"
            }]
        }

    async def _stream(self, cmd):
        proc = await asyncio.create_subprocess_exec(
            *cmd, env=self.env, stdout=asyncio.subprocess.PIPE
        )
        async for line in proc.stdout:
            if not line.strip():
                continue
            event = json.loads(line)
            if event.get("type") == "text":
                yield {"choices": [{"delta": {"content": event["data"]}}]}
            elif event.get("type") == "end":
                yield {"choices": [{"delta": {}, "finish_reason": "stop"}]}


async def main():
    client = GrokChat(cwd=".")
    response = await client.create(
        [{"role": "user", "content": "What files are here?"}]
    )
    print(response["choices"][0]["message"]["content"])

asyncio.run(main())

#סקריפט Shell

#!/bin/bash
# Run a code review and exit with failure if issues are found

RESULT=$(grok -p "Review this PR for bugs. Output JSON with 'issues' array." \
  --output-format json --yolo | jq -r '.text')

ISSUE_COUNT=$(echo "$RESULT" | jq '.issues | length' 2>/dev/null || echo "0")

if [ "$ISSUE_COUNT" -gt 0 ]; then
  echo "Found $ISSUE_COUNT issues"
  echo "$RESULT" | jq '.issues[]'
  exit 1
fi

echo "No issues found"

#אישור תמידי לאוטומציה

--always-approve (כינוי --yolo, זהה ל---permission-mode bypassPermissions) מריץ קריאות כלים בלי בקשות הרשאה אינטראקטיביות. כללי דחייה, הוקים ונעילות מנהל עדיין חלים (ראו הרשאות ובטיחות).

בלי אישור תמידי, כולל --permission-mode plan, קריאת כלי שצריכה אישור נדחית, מכיוון שהרצה headless אינה יכולה לשאול, ו-stderr מציין את הקריאה פעם אחת: permission required: Edit calc.py was not run, as a headless run cannot ask for approval. ההערה מודפסת רק כאשר ההרצה מקבלת בקשת אישור, ודחיות במצב plan קורות לפני כן. קוד היציאה נשאר 0.

בנתיב ה-daemon, אישור שקריאת host של הרצת workflow ברקע צריכה מוכרע באותו אופן. בזמן שהרצה headless ממתינה לעבודה ברקע אחרי התור שלה, stderr מציין את ה-workflow: permission required: Edit REVIEW.md (workflow "review") was not run, as a headless run cannot ask for approval. בזמן שהתור רץ, האישור של ההרצה נשאל באותו תור כמו קריאות הכלים של התור עצמו, והשורה מציינת רק את הקריאה. ההרצה מקבלת את הדחייה, והרצה שנכשלת אחר כך קובעת את קוד היציאה (ראו Workflows ועבודה ברקע).

grok -p "Format all files" --always-approve
grok -p "Run the tests and fix any failures" --cwd ~/projects/my-app --always-approve

עבור שרתי סוכן ו-SDK, ראו מצב סוכן.


#תוכניות שנשמרו בנתיב ה-daemon

בנתיב ה-daemon, תור grok -p ששומר תוכנית שולח המשך אחד שמבקש מהסוכן לבנות את התוכנית. ההמשך נשלח כאשר התור מסתיים ב-end_turn. --permission-mode plan, --json-schema ו---max-turns אינם שולחים המשך, והתוכנית שנשמרה נשארת לא בנויה. תוכנית שנשמרת במהלך הבנייה נשארת לא בנויה.

כאשר ההמשך נשלח, usage של התוצאה מסכם את שני התורות ו-requestId מציין את תור הבנייה. התוצאה כוללת עלות כאשר שני התורות מציינים אחת ואף חשבון אינו חלקי או לא שלם. כאשר תור אחד מציין עלות והאחר חייב טוקנים ולא ציין אף אחת, או שאחד החשבונות כבר חלקי, התוצאה משמיטה את העלות ומגדירה cost_is_partial. כאשר שני התורות חייבו טוקנים ואף אחד לא ציין עלות, ואף חשבון אינו חלקי או לא שלם, התוצאה משמיטה את העלות ואינה מגדירה אף דגל. חשבון לא שלם משמיט את העלות ומגדיר usage_is_incomplete. חשבון תכנון שנרשם משמיט את העלות ומגדיר usage_is_incomplete כאשר תור הבנייה לא מביא חשבון. תור תכנון שלא מביא חשבון משאיר את התוצאה לא שלמה, בלי עלות, בין אם תור הבנייה מביא חשבון ובין אם לא. כאשר אף תור לא מביא חשבון, התוצאה מגדירה usage_is_incomplete ואין לה עלות. התוצאה משמיטה את num_turns כאשר רק תור אחד מציין אותו. מודל שרק תור אחד השתמש בו שומר את ספירת הקריאות של אותו תור. מודל ששני התורות השתמשו בו שומר ספירת קריאות רק כאשר שני התורות ציינו אחת.


#משתני סביבה ל-headless

משתני סביבה מרכזיים שמשפיעים על מצב headless:

משתנהתיאור
XAI_API_KEYמפתח API לאימות (נדרש כאשר אין התחברות בדפדפן)
GROK_HOMEדריסת תיקיית ההגדרות (ברירת מחדל: ~/.grok)
GROK_LOG_FILEנתיב לקובץ לוג (בשימוש כלשונו כנתיב, עובד ב-headless וב-TUI, מכבד את RUST_LOG)
RUST_LOGמסנן רמת לוג (לדוגמה debug). לוגים של headless נכתבים ל-stderr.

עבור סביבות CI בלי גישה לדפדפן, הגדירו את XAI_API_KEY עם מפתח API מ-console.x.ai:

export XAI_API_KEY="xai-..."
grok -p "Run the test suite" --yolo

#Workflows ועבודה ברקע

הרצה headless ממתינה לעבודה ברקע שהיא התחילה לפני שהיא יוצאת, עד 10 דקות אחרי שתור אחרון מסתיים. --background-wait-timeout <secs> קובע מגבלה אחרת. כאשר משימת shell ברקע או subagent מסתיימים, המודל מקבל את התוצאה בתור חדש (תור auto-wake, או תור ההתראה ש-idle drain מריץ כאשר auto-wake כבוי). ההרצה headless מדפיסה את התשובה הזו אחרי הטקסט של התור הראשון, כפסקה משלה, וממתינה שהתור הזה יסתיים. מגבלת ההמתנה אף פעם לא קוטעת תור שרץ באמצע: היא נספרת מסוף התור האחרון וחלה רק בזמן שההרצה ממתינה לעבודה ברקע.

עבודה שעדיין רצה כאשר ההמתנה נגמרת נעצרת, וההרצה אז יוצאת 1 ואומרת מה היא עצרה, כגון the wait for background work ran out after 600 s and exit stopped 1 background task (…). העבירו --no-wait-for-background כדי לצאת ברגע שהתור הראשון מסתיים. היציאה עוצרת את העבודה שעדיין רצה. בנתיב ה-daemon, ההרצה אז מפרטת ב-stderr מה היא עצרה: שורה לכל הרצת workflow, כגון workflow slow (run wf_…) was still running at exit and was stopped: the run did not wait …, ואז אחת לשאר, כגון the run did not wait for background work (--no-wait-for-background) and exit stopped 1 other background job. היא לא מדפיסה כלום כאשר שום דבר לא רץ, ומציינת זאת כאשר היציאה לא יכלה לעצור את העבודה, או לא יכלה לקרוא את הרצות ה-workflow מבין מה שהיא עצרה. העבודה הזו התבקשה ואינה משנה את קוד היציאה: לא נכתב אירוע error, ושורת הסגירה שומרת את סיבת העצירה של התור.

--background-shell-timeout <secs> מגביל רק shells ברקע, ורק כאשר הסשן רץ על ה-daemon: ברגע ש-shells רצו כל כך הרבה אחרי שהתור האחרון הסתיים, בלי תור חדש או משימת רקע שהסתיימה מאז, ההרצה עוצרת אותם בלי להתחיל תור עבורם וממשיכה להמתין ל-subagents ברקע בלי מגבלה. ההרצה לא נכשלת בגלל ה-shells שנעצרו. זה מחליף את מגבלת ההמתנה הכוללת, ולכן אי אפשר לשלב אותו עם --background-wait-timeout, והוא לא מגביל את ההמתנה על מטרה פעילה.

בנתיב ה-daemon, הרצת workflow היא גם עבודה ברקע. כאשר הרצה שהמודל התחיל ברקע מסתיימת, המודל מקבל את תוצאת ההרצה בתור חדש. ההרצה headless מדפיסה את התשובה הזו אחרי הטקסט של התור הראשון, ואז יוצאת. עם --output-format json, התשובה היא חלק מ-text. ההמתנה גם מסתיימת כאשר העבודה ברקע היחידה שנשארה היא הרצות שהושהו בתקציב הסוכן שלהן: הרצה headless אינה יכולה להעלות תקציב. היציאה אז עוצרת את ההרצות האלה, כך שחידוש מאוחר יותר גם אינו יכול להעלות אותו.

פקודות workflow עובדות בהרצה headless בנתיב ה-daemon:

  • grok -p '/<name> [--agent-budget N] [args]' ו-grok -p '/workflow <name> [args]' מתחילים workflow מהרשימה ישירות, עם התקציב שאתם מעבירים, וממתינים לו כמו לעיל. התחלה שנדחית, כגון /deep-research בלי שאילתה, מכשילה את ההרצה headless עם הסיבה. workflow מסוג .rhai שה-daemon אינו יכול להתחיל עדיין עובר למודל כטקסט, ו-/workflow list מציין זאת.
  • grok -p '/workflow list' ו-grok -p '/workflow help' עונים מיד, בלי תור מודל. כך גם /workflow runs, stop ו-resume, אבל כל הרצה headless מתחילה daemon משלה, ולכן הן לא רואות הרצה של הרצה headless קודמת. פקודת /workflow שנכשלת, כגון stop בלי הרצה לעצור, מכשילה את ההרצה headless עם הסיבה.
  • בתיקייה שלא נתתם בה אמון, Grok אינו קורא את .grok/workflows של הפרויקט. /workflow list מציין את ה-workflows שהושמטו, ו-/<name> או /workflow <name> עבור אחד מהם מכשיל את ההרצה headless עם הסיבה הזו. העבירו --trust כדי לתת אמון בתיקייה.

הרצת הרקע החדשה ביותר של כל workflow קובעת את קוד היציאה, אלא אם הרצה חדשה יותר שלו הושלמה. אם ההרצה הזו לא הושלמה, ההרצה headless יוצאת 1, ו-stderr אומר איזו הרצה ולמה:

ההרצה החדשה ביותרמה stderr אומר
נכשלה, כולל הרצה שנכשלה בהתחלהworkflow gate (run wf_…) failed: Error: GATE-FAILED: 2 checks red
הושהתה בתקציב הסוכן שלה, שהרצה headless אינה יכולה להעלותworkflow deep-research (run wf_…) paused at its agent budget (3 of 3 agents used)
עדיין רצה כאשר ההמתנה נגמרהworkflow slow (run wf_…) was stopped after 600 s: the wait for background work ran out. …
עדיין רצה ביציאה אחרי שההמתנה הסתיימה, כגון הרצה שתור מאוחר יותר של מטרה התחילworkflow slow (run wf_…) was still active at exit and was stopped: it was still going after the wait for background work ended

הרצה שנכשלה ואז הורצה מחדש עד השלמה באותה הרצה headless, ברקע או בחזית, אינה מכשילה אותה. הרצה שהמודל הריץ בחזית אף פעם לא מכשילה אותה: התוצאה שלה הגיעה למודל באותו תור. אם אי אפשר לקרוא את ההרצות אחרי שלסשן היו הרצות workflow, אחרי שמטרה המשיכה לתור נוסף לאחר שההמתנה הסתיימה, או אחרי שההמתנה נגמרה, ההרצה יוצאת 1 ומציינת זאת. אחרת היציאה אינה מפרטת אותן. עבודת רקע אחרת שנעצרת כאשר ההמתנה נגמרת, כגון shell, גם מכשילה את ההרצה (… exit stopped 2 background jobs). הרצת workflow שהיציאה עצרה (עדיין רצה או מושהית) מצוינת בשורה משלה ומושמטת מהספירה, שאז אומרת other. רק ההרצה החדשה ביותר של כל workflow מקבלת שורה, ולכן הרצה ישנה יותר של אותו workflow שעדיין נמשכת נספרת עם שאר העבודות. מחוץ למטרה, אם תור שהסוכן מריץ אחרי הפרומפט נכשל, כגון התור שעונה עם תוצאת workflow או עם משימת רקע שהסתיימה, ההרצה יוצאת 1 ו-stderr אומר למה: a turn the agent ran after the prompt failed: …. תור שנקטע במגבלת הפלט שלו גם מכשיל את ההרצה, כמו פרומפט קטוע: a turn the agent ran after the prompt stopped at its output limit, so its reply is cut short. תור שמסתיים כרגיל אינו עושה זאת. התורות של מטרה עצמה מדווחים לפי תוצאת המטרה.

עם --output-format json או פורמט streaming, הפלט מסתיים באובייקט השגיאה במקום התוצאה, בלי מזהה הסשן. כדי לחדש סשן כזה, בחרו את המזהה שלו מראש עם -s <uuid>. הרצה שנעצרת כאשר ההמתנה נגמרת אינה משאירה תוצאה.


#קודי יציאה

קודמשמעות
0הצלחה. הפרומפט הושלם כרגיל
1שגיאה. כשל אימות, שגיאת רשת, או שגיאת זמן ריצה. בנתיב ה-daemon, גם הרצת workflow שלא הסתיימה, או, מחוץ למטרה, תור כושל שהסוכן הריץ אחרי הפרומפט (ראו Workflows ועבודה ברקע)
130הופרע על ידי SIGINT (Ctrl+C)
143הופסק על ידי SIGTERM

#אימות לסביבות headless

לשימוש headless, אמתו באחת מהאפשרויות:

אם התחברתם בעבר, פרטי התחברות שנשמרו במטמון משמשים אוטומטית.


#טיפים

  • מצב headless מתחיל סשן חדש כברירת מחדל. השתמשו ב--r/--resume או ב--c/--continue כדי לשמור הקשר בין קריאות.
  • התשובה של --output-format json תמיד כוללת sessionId שאפשר להשתמש בו עם --resume לקריאות המשך.
  • שלבו --yolo עם --rules כדי לקבוע גדרות: grok -p "..." --yolo --rules "Never delete files".
  • לניפוי שגיאות, העלו את רמת הלוג ולכדו את stderr: RUST_LOG=debug grok -p "..." 2> debug.log.

#גילוי שורש הפרויקט

כאשר Grok מתחיל, הוא מגלה את שורש הפרויקט על ידי הליכה כלפי מעלה מ---cwd (או מהתיקייה הנוכחית) עד שהוא מוצא תיקיית .git.

הערה: אם --cwd מקונן בתוך מאגר גדול (כגון monorepo), Grok מגלה את המאגר הזה כשורש הפרויקט ומגביל את הגילוי שלו (AGENTS.md, skills, היסטוריית git) אליו, מה שיכול להאט את ההפעלה. כוונו את --cwd אל תת הפרויקט הספציפי שבו אתם רוצים לעבוד כדי לשמור על היקף קטן.

#מיקומי קבצים

גרוק שומר נתונים ב-~/.grok (דריסה באמצעות GROK_HOME. ראו משתני סביבה ל-Headless):

נתיבתוכן
config.tomlהגדרות משתמש
auth.jsonאישורי OAuth2/API שמורים במטמון
version.jsonמטמון גרסה לבדיקות עדכון
sessions/תמלילי סשנים (SQLite)
memory/מאגר זיכרון בין סשנים
logs/קובצי לוג פנימיים (למשל unified.jsonl)
logs/mcp/לוגי שרת MCP
skills/הגדרות skill של המשתמש
personas/פרסונות סוכן בהיקף המשתמש
crash/דוחות קריסה
trace-exports/ייצואי מעקב של סשנים
worktrees/מטא-נתונים של עצי עבודה של Git

#~/.grok לקריאה בלבד

למכולות או ל-CI, עגנו את ~/.grok לקריאה בלבד:

  • מלאו מראש את auth.json או השתמשו ב-XAI_API_KEY
  • שמירת הסשן נכשלת בשקט (ארעי)
  • בדיקות עדכון רושמות אזהרה ומדלגות
export XAI_API_KEY="xai-..."
export GROK_DISABLE_AUTOUPDATER=1
grok -p "..." --no-auto-update

#דיכוי בדיקת עדכונים

שיטההיקף
--no-auto-updateסשן
GROK_DISABLE_AUTOUPDATER=1תהליך
stderr שאינו TTY (מזוהה אוטומטית)אוטומטי
[cli] auto_update = falseקבוע

הגדרת GROK_DISABLE_AUTOUPDATER לערך שקרי (0, false, off, no, או ריק, בכל רישיות) נחשבת כלא מוגדר. ערכות ה-SDK של הסוכן מזריקות GROK_DISABLE_AUTOUPDATER=1 לסוכנים שאינם המוביל שהן מפעילות (ערך שקרי בסביבת הבידוד של ה-SDK משאיר את העדכונים פעילים), וסוכן ה-stdio מדלג על עדכון הרקע שלו אלא אם הוא רץ מההתקנה המנוהלת ($GROK_HOME/bin/grok).

הודעות עדכון הולכות ל-stderr. stdout נשאר נקי עבור --output-format json. ראו גם משתני סביבה ל-Headless.


#דגלים נוספים למצב Headless

הדגלים האלה משלימים את טבלת אפשרויות שורת הפקודה למעלה. דגלים שכבר רשומים שם (--prompt-json, --prompt-file, --verbatim, --sandbox, --no-auto-update) לא חוזרים כאן.

דגלתיאור
--agent <NAME>שם סוכן או נתיב לקובץ הגדרה
--agents <JSON>הגדרות תת-סוכנים מוטמעות כ-JSON
--system-prompt-overrideדריסת הנחיית המערכת של הסוכן
--no-planהשבתת מצב תוכנית
--no-subagentsהשבתת יצירת תת-סוכנים
GROK_MEMORY=0השבתת זיכרון בין סשנים עבור התהליך
--disable-web-searchהשבתת חיפוש באינטרנט וכלי שליפה
--no-alt-screenהרצה בתוך השורה (בלי מסך חלופי)
--worktree [NAME]יוצר עץ עבודה של git מה-checkout הנוכחי (כולל שינויים שלא נשמרו) ומריץ את הסשן שם. הפעלה מתת-ספרייה נוחתת באותה תת-ספרייה של עץ העבודה. בסשן חדש, אם לעץ העבודה חסרה הספרייה הזאת, למשל ספרייה שמתעלמים ממנה או ספרייה שהקומיט של --worktree-ref קודם לה, הסשן נפתח בשורש עץ העבודה ו-grok מדפיס הערה שאומרת זאת. עם -r, הסשן ממשיך לתוך עץ העבודה החדש. אי אפשר לשלב עם --fork-session. תחת פרופיל sandbox שלא יכול ליצור עצי עבודה, למשל strict, grok יוצא עם שגיאה לפני שהסשן מתחיל (ראו מצב Sandbox).
--ref <REF> / --worktree-ref <REF>ענף, תג או קומיט שעליו לבסס את עץ העבודה (עם --worktree). checkout נקי, בלי שכבת שינויים שלא נשמרו

#ריצות Headless שהופסקו

ב-SIGINT או ב-SIGTERM:

  • מצב הסשן נשמר עד קריאת הכלי האחרונה שהושלמה
  • שינויי קבצים על ידי כלים לא מגולגלים לאחור
  • קוד היציאה הוא 130 עבור SIGINT (128 + 2) ו-143 עבור SIGTERM (128 + 15). צינורות CI יכולים להבחין ביניהם לבין שגיאה רגילה (קוד יציאה 1)
  • אחרי שהפרומפט נשלח, הריצה עוצרת את עבודת הרקע שהתחילה, מסיימת את הפלט שלה, ואז יוצאת. עצירת העבודה הזאת יכולה להחזיק את שורת הסגירה עד 10 שניות, והיציאה יכולה להגיע מאוחר יותר בזמן שהסוכן נכבה. במסלול המעטפת הסוכן קודם מסיים את בקשות העצירה שנשלחו אליו. רתמה ששולחת SIGTERM צריכה להמתין יותר מברירת המחדל של 10 שניות של docker stop לפני שהיא שולחת SIGKILL. תוצאה שהוכרעה לפני האות מסיימת את הפלט בשורה שהייתה לה בלי האות, למשל שגיאה של פרומפט שנכשל, תור שנעצר בגלל refusal או max_tokens, מגבלת התורות, תור שנכשל שהסוכן הריץ אחרי הפרומפט, ריצת יעד או זרימת עבודה שכבר הסתיימה בלי להשלים, גם לפני שההמתנה ענתה, המתנה שכבר נגמרה, עם שורה לכל ריצת זרימת עבודה שהיא קצצה, או ריצה שכבר סיימה להמתין. ריצת זרימת עבודה שהיציאה לא יכלה לעצור שומרת גם על השורה שלה. ריצות שאי אפשר לקרוא אחרי אות שהגיע לפני שההמתנה ענתה לא מכשילות את הריצה. כל דבר אחר מסתיים ב-cancelled: streaming-json עם end ש-stopReason שלו הוא cancelled, streaming-messages-json עם result מתת-סוג error_during_execution ו-stop_reason cancelled, ו-json עם stopReason cancelled של האובייקט שלו. json לא מדפיס דבר כשהפרומפט מעולם לא ענה, ופלט רגיל לא מדפיס דבר נוסף. תחת --no-wait-for-background במסלול ה-daemon, הריצה עדיין מפרטת ב-stderr מה היציאה עצרה כשאות מגיע אחרי שהתור הסתיים
  • נעצר במהלך התור: ל-end הזה יש requestId ריק ו-usage_is_incomplete: true, ו-usage של ה-result משמיט את התור שקוצץ (אפסים בכל השדות כשזה היה התור היחיד של הריצה), לכן יש לקרוא אותו כחסם תחתון. נעצר בזמן המתנה לעבודת רקע: שורת הסגירה נושאת את שדות ההוצאה של כל תור שהסתיים, ו-end ואובייקט ה-json נושאים את requestId של התור שענה. במסלול ה-daemon, תור שהעצירה קצצה אחרי שהתחיל, יעד שעדיין רץ, או עצירה שנכשלה, גורמים להם להיות usage_is_incomplete: true בלי עלות
  • אות בזמן שהסשן עדיין מתחיל יוצא מיד, בלי שורת סגירה. אות שני כופה את היציאה: הריצה לא ממתינה שעבודת הרקע שלה תיעצר, והפלט עלול להסתיים בלי שורת הסגירה שלו
  • חידוש: grok -p "continue" --resume "<id>" או grok -p "continue" --continue

ראו ניהול סשנים במצב Headless לפרטים על סשנים בעלי שם ועל הדגלים -s/-r/-c.