מדריך קלוד קוד בעברית

תיעוד 104

התאמה אישית של הפעלות בסביבות באירוח עצמי

התאמה אישית של הפעלות בסביבה באירוח עצמי בעזרת סקריפטים עוטפים (wrapper scripts) עבור אישורי גישה ייעודיים לכל הפעלה, ווי מחזור חיים (lifecycle hooks), והרצה של רנרים לפי דרישה.

הערה: סביבות באירוח עצמי (self-hosted environments) נמצאות בבטא ציבורית בתוכניות Team ו-Enterprise. בעלים (Owner) מפעיל אותן על ידי הפעלת האפשרות Allow self-hosted environments בדף הניהול Cloud environments. דף זה מניח שקיים רנר פעיל, ראו את מדריך ההתחלה המהירה להגדרה ואת פריסה לסביבת ייצור למתכוני פריסה של צי רנרים.

סביבה באירוח עצמי (self-hosted environment) מריצה הפעלות ענן של Claude Code (cloud sessions) על גבי התשתית שלכם, באמצעות תהליך רנר (runner) שאתם פורסים. ללא הגדרת תצורה מיוחדת, הרנר משכפל את מאגר הקוד של ההפעלה, מפעיל את Claude Code, ומבצע ניקוי בסיום. דף זה מיועד למהנדסי פלטפורמה שמפעילים את הרנרים: הוא מכסה את נקודות ההרחבה למקרים שבהם ברירות המחדל אינן מתאימות, החל מאספקת אישורי גישה ייעודיים לכל הפעלה ועד להחלפה מלאה של שלב ה-checkout. עוטפים (wrappers) ווים (hooks) רצים כקבצים הניתנים להפעלה במארח של הרנר, שהוא Linux או macOS, והדוגמאות בדף זה מניחות שימוש במעטפת תואמת POSIX shell.

מספר משתני סביבה של ווים בדף זה עדיין משתמשים ב-pool, כגון CLAUDE_RUNNER_POOL_ID. שמות הדגלים ב-CLI ומשתני הסביבה משתמשים ב-environment, כגון --environment-secret-file.

#סקריפטים עוטפים (Wrapper scripts)

השתמשו בסקריפט עוטף כאשר כל הפעלה זקוקה להכנה שהרנר אינו יכול לבצע בעצמו: הקצאת אישורי גישה קצרי מועד המוגדרים ליוצר ההפעלה, ייצוא סודות ייעודיים לסביבה, הכנת כלי פיתוח של שפות תכנות, או החלת מגבלות משאבים על תהליך הבן. הרנר מפעיל את העוטף שלכם במקום את הקובץ הבינארי של Claude Code, פעם אחת בכל הפעלה. סיימו את העוטף על ידי פקודת exec אל $CLAUDE_RUNNER_CLAUDE_BIN, הקובץ הבינארי של הרנר עצמו, כדי שאותות (signals) וקודי יציאה יועברו כראוי.

הפנו את הדגל --exec-path, או את משתנה הסביבה SELF_HOSTED_RUNNER_EXEC_PATH, אל הסקריפט העוטף בעת הפעלת הרנר:

claude self-hosted-runner --environment-secret-file /etc/claude/environment-secret --exec-path /etc/claude/session-wrapper.sh

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

משתנהתיאור
CLAUDE_CODE_SESSION_ACCESS_TOKENטוקן ה-JWT של ההפעלה, עם הקידומת sk-ant-cc-. תביעת (claim) ה-act שבו מזהה את יוצר ההפעלה, יחד עם כתובת האימייל של היוצר ומזהה ה-subject מספק הזהויות (identity provider) החיצוני, כאשר הממשק שיצר את ההפעלה רשם אותם. הערך הוא הטוקן בעת יצירת התהליך. רענונים של הטוקן מגיעים דרך ה-stdin של תהליך הבן, ולכן עוטף רואה רק את הערך הראשוני. ראו אימות זהות הפעלה.
CCR_SESSION_ACCOUNT_EMAILכתובת האימייל של יוצר ההפעלה, שחולצה מראש על ידי הרנר מתוך תביעת act.email של הטוקן ללא אימות חתימה. מתאימה לתיוג, כגון הערות בסיום הודעות commit (כגון commit trailers). כאשר כתובת האימייל קובעת הנפקת אישורי גישה, אמתו את הטוקן וקראו את התביעה מתוכו במקום זאת, ראו הקצאת אישורי גישה המוגדרים ליוצר ההפעלה. אינו מוגדר כאשר הטוקן אינו מכיל אימייל של היוצר. יש להתייחס למידע זה כמידע המזהה אדם באופן אישי (PII).
CLAUDE_RUNNER_CLIENT_PLATFORMממשק הלקוח שיצר את ההפעלה, כגון web_claude_ai, desktop_app, ios, claude_code_cli, או scheduled_trigger. חברת Anthropic רושמת את הערך פעם אחת בעת יצירת ההפעלה, כך שהעוטף וכל ווי מחזור החיים רואים את אותו הערך. השתמשו בו לצורכי ניתוח נתוני שימוש (adoption analytics) ותיוג בלבד, ולא כאות לאימות הרשאות. אינו מוגדר כאשר להפעלה אין ממשק מתועד או מוכר, לכן פנו אליו כ-${CLAUDE_RUNNER_CLIENT_PLATFORM:-} תחת set -u. דורש את Claude Code בגרסה v2.1.229 ומעלה.
CLAUDE_RUNNER_CLAUDE_BINנתיב מוחלט לקובץ הבינארי של Claude Code של הרנר עצמו. סיימו את העוטף שלכם באמצעות exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" כדי להעביר את השליטה לקובץ הבינארי המקובע מבלי לקבע נתיב התקנה בקוד.
CLAUDE_CODE_REMOTE_SESSION_IDמזהה ההפעלה במבנה עם קידומת cse_.... זוהי אותה הפעלה שווי מחזור החיים רואים כ-CLAUDE_RUNNER_SESSION_ID במבנה session_.... משתני ה-UUID תואמים בשניהם, והחלפת הקידומת cse_ ב-session_ מניבה את המזהה המוצג בכתובת ה-URL של ההפעלה.
CLAUDE_CODE_REMOTE_SESSION_UUIDאותו מזהה הפעלה במבנה UUID תקני, עבור מערכות המשתמשות ב-UUID כמפתח.
CLAUDE_SESSION_INGRESS_TOKEN_FILEנתיב מוחלט לקובץ ייעודי להפעלה המכיל את ה-JWT הנוכחי של ההפעלה, המתעדכן לאורך רענוני טוקן. תהליכי בן במעטפת קוראים אותו עבור כותרת ה-Authorization שלהם בעת הורדת קבצים מצורפים שהמשתמש הוסיף להפעלה. פקודת exec משמרת את המשתנה באופן אוטומטי. עוטף שבונה מחדש את סביבת תהליך הבן חייב להעביר את המשתנה הלאה, אחרת הורדות של קבצים מצורפים יפסיקו לפעול באופן שקט.
CLAUDE_CONFIG_DIRספריית תצורה של Claude ייעודית להפעלה, שנכתבת בתחילת ההפעלה מתוך תמונת מצב (snapshot) של תצורת מארח הרנר שהרנר לוכד בעת ההפעלה, ראו הרשאות ואישור כלים. פעולות כתיבה כאן מבודדות להפעלה זו בלבד.
ANTHROPIC_BASE_URLכתובת ה-URL הבסיסית של ה-API שתשמש את תהליך הבן, הנמסרת על ידי מישור הבקרה (control plane) לכל הפעלה ובאופן רגיל היא https://api.anthropic.com. אל תדרסו אותה: אישור הגישה להסקה (inference) של ההפעלה הוא טוקן OAuth שהונפק על ידי Anthropic שספקים אחרים אינם מקבלים, כך שלא ניתן לנתב הסקה בסביבות באירוח עצמי למקום אחר.
CLAUDE_CODE_OAUTH_TOKENטוקן גישה קצר מועד מסוג OAuth שתהליך הבן משתמש בו להסקת מודל, המוגבל להסקת מודל ולהעלאת קבצים בלבד, עם משך חיים של כ-30 דקות. הרנר מנפיק אותו מחדש לפני פקיעת התוקף ומעביר את הסבב דרך ה-stdin של תהליך הבן, כך שעוטף שאינו שומר על חיבור של stdin יראה רק את הערך הראשוני. אל תסתמכו על רשימת כתובות ה-IP המורשות של הארגון שלכם כדי להגביל את השימוש בטוקן זה: התייחסו אליו כאישור גישה למחזיק (bearer credential) שנשאר שמיש למשך כ-30 דקות אם הוא דולף, ואל תתעדו אותו ביומן, אל תכתבו אותו לדיסק, ואל תעבירו אותו מחוץ למכולת ההפעלה (container).

העוטף יורש גם את שאר הסביבה המנוהלת של תהליך הבן, כולל כל משתנה סביבה שמספק השרת. פקודת exec מעבירה את הכל באופן אוטומטי. אם העוטף שלכם מפעיל את תהליך הבן בדרך אחרת, העבירו את הסביבה המלאה.

#שמירה על חיבור של stdin ומתאר קובץ 3

ה-stdin של תהליך הבן הוא ערוץ הבקרה של הרנר. עדכוני טוקן בסבב ואותות סיום הפעלה מגיעים דרכו. הרנר גם פותח צינור (pipe) במתאר קובץ 3 (file descriptor 3) וקורא ממנו אותות פעילות של תהליך הבן כדי לנהל זמני קצוב לחוסר פעילות ולהפעלה. פקודת exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" פשוטה משמרת את שניהם באופן אוטומטי.

אם העוטף שלכם מעביר את תהליך הבן לרקע באמצעות & בלבד, הוא מנתק את ה-stdin של תהליך הבן: ההפעלה תיראה תקינה עד שמשך החיים הראשוני של טוקן ה-OAuth, כ-30 דקות, יפוג, ואז כל קריאת API תיכשל עם שגיאת 401 authentication_error. אם העוטף שלכם חייב להעביר את תהליך הבן לרקע, למשל כדי להשאיר מלכודת פירוק (teardown trap) פעילה, שמרו את stdin במתאר קובץ 4 ומעלה וחברו אותו מחדש במפורש:

exec 4<&0
"$CLAUDE_RUNNER_CLAUDE_BIN" "$@" <&4 4<&- &
CHILD=$!
trap 'teardown' EXIT
wait "$CHILD"

אל תסגרו ואל תשתמשו מחדש במתאר קובץ 3 בתוך העוטף. ניתוב מחדש של stdout ו-stderr של תהליך הבן מותר.

#הקצאת אישורי גישה המוגדרים ליוצר ההפעלה

השתמשו בתת-הפקודה decode-token כדי לקרוא תביעות מתוך ה-JWT של ההפעלה. היא קוראת את הטוקן מתוך ארגומנט, מתוך CLAUDE_CODE_SESSION_ACCESS_TOKEN, או מתוך stdin, לפי סדר זה. ראו אימות הטוקן בתוך ההפעלה לגבי מה שהיא בודקת. הדוגמה להלן מפענחת את זהות היוצר, ממירה אותה לאישורי גישה קצרי מועד של AWS, ומבצעת exec לתוך Claude Code:

#!/bin/bash
# Key on the stable Anthropic user ID and require a human creator.
CREATOR_SUB=$("$CLAUDE_RUNNER_CLAUDE_BIN" self-hosted-runner decode-token \
  | jq -re '.act.sub // "" | select(startswith("user:"))') \
  || { echo "decode-token: verification failed or no human creator" >&2; exit 1; }

creds=$(your-sts-helper assume-role --subject "$CREATOR_SUB") \
  || { echo "credential exchange failed" >&2; exit 1; }
eval "$creds"

exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"

השתמשו ב-jq -re ולא ב-jq -r כאשר התביעה שחולצה משמשת לקבלת החלטת הרשאה, כך שתביעה חסרה תגרום ליציאה עם קוד שגיאה (ערך שאינו אפס) במקום להעביר את המחרוזת null במורד הזרם. הפעלות שנוצרו על ידי זהות שירות של הארגון, כגון הפעלות של בוטים וסוכנים, נושאות subject עם agent: במקום user:, ולכן דוגמה זו דוחה אותן. אם הסביבה שלכם משרתת הפעלות מסוג זה, החליטו במפורש האם העוטף נסוג לאישור גישה כברירת מחדל עבורן במקום לצאת בשגיאה. כאשר החלפת אישורי הגישה שלכם דורשת את ה-subject של ה-SSO או את האימייל במקום זאת, קראו את .act.attested_by.sub או .act.email וטפלו בהיעדרם: הטוקן נושא אותם רק כאשר ממשק היצירה תיעד אותם, ובהפעלה שנשלחה דרך ה-CLI שניהם עשויים להיות חסרים. לתיעוד המלא של התביעות ולאימות משירותים מחוץ לרנר, ראו אימות זהות הפעלה.

#ווי מחזור חיים (Lifecycle hooks)

ווי מחזור חיים מחליפים שלבים בצינור העבודה (pipeline) של הרנר לכל הפעלה בסקריפטים משלכם. הפנו את הרנר לספריית ווים באמצעות הדגל --hooks-dir <path>, או משתנה הסביבה SELF_HOSTED_RUNNER_HOOKS_DIR. הרנר מחפש קבצים ברי הפעלה בעלי שמות מוכרים מראש. כל וו שאינו קיים עובר להתנהגות המובנית של המערכת, כך שאתם כותבים רק את הווים הדרושים לכם. ווים רצים עם ההרשאות של הרנר עצמו, ותהליכי הבן של ההפעלה חולקים את אותו ה-UID, לכן עגנו (mount) את ספריית הווים לקריאה בלבד (read-only), או הטמיעו אותה בתוך ה-image, כך שקוד ההפעלה לא יוכל לשנות אותה. ראו את סעיף הקשחת האבטחה.

ווים אלה נפרדים מווי Claude Code, אשר רצים בתוך ההפעלה. ווי מחזור חיים רצים על גבי הרנר, מסביב להפעלה.

#checkout

רץ פעם אחת לכל מאגר קוד, במקום פעולות ה-clone וה-fetch המובנות של הרנר. השתמשו בוו זה כדי לשכפל משרת מראה לקריאה (read-through mirror), להזין עץ עבודה מתוך ארכיון, או להחיל אימות git ייעודי לכל הפעלה. הרנר מגדיר:

משתנהתיאור
CLAUDE_RUNNER_REPO_URLכתובת ה-URL של המאגר לשכפול, לאחר החלת כל כללי --git-host-rewrite ו---git-ssh-rewrite
CLAUDE_RUNNER_REPO_REFהגרסה (revision) לשליפה (checkout): ענף, תגית, או SHA של commit כפי שביקשה ההפעלה. ערך ריק מציין את ענף ברירת המחדל של המאגר.
CLAUDE_RUNNER_CHECKOUT_PATHנתיב מוחלט שבו יש להשאיר את עץ העבודה
CLAUDE_RUNNER_SESSION_IDמזהה ההפעלה במבנה עם קידומת session_..., לצורכי רישום יומן וקורלציה
CLAUDE_RUNNER_SESSION_UUIDאותו מזהה הפעלה במבנה UUID תקני
CLAUDE_RUNNER_API_BASE_URLכתובת ה-URL הבסיסית של API של Anthropic עבור קריאות בהיקף ההפעלה
CLAUDE_RUNNER_CLIENT_PLATFORMממשק הלקוח שיצר את ההפעלה, כגון web_claude_ai, desktop_app, או ios. אינו מוגדר כאשר להפעלה אין ממשק מתועד או מוכר.
CLAUDE_CODE_SESSION_ACCESS_TOKENטוקן הגישה של ההפעלה, עבור קריאות API בהיקף ההפעלה

הסקריפט חייב להשאיר עץ עבודה ב-CLAUDE_RUNNER_CHECKOUT_PATH כאשר הגרסה המבוקשת שלופה בו. מצב Detached HEAD תקין, כיוון שהרנר יוצר את ענף העבודה של ההפעלה מעליו. הרנר מוודא לאחר מכן שהנתיב מכיל ספריית .git. אם הוו שלכם מייצר מקור שאינו git, כגון Perforce או ארכיון tarball שנפרס, הגדירו CLAUDE_RUNNER_SKIP_GIT_VERIFY=1 בסביבת הרנר כדי לדלג על בדיקה זו. תהליכים מבוססי git, כגון יצירת ענף עבודה ודחיפת תוצאות, דורשים checkout של git, לכן יצאו תוצאות מעצים שאינם git באמצעות וו post-session.

הרנר אינו מעביר אישורי גישה של git לוו. במקום זאת, הפיקו אישור גישה לשכפול ייעודי להפעלה מתוך זהות ההפעלה: אמתו את CLAUDE_CODE_SESSION_ACCESS_TOKEN באמצעות ספריית JWT סטנדרטית מול נקודת הקצה JWKS תחת CLAUDE_RUNNER_API_BASE_URL, כמתואר באימות הטוקן מהשירות שלכם, ולאחר מכן הגדירו לשירות אישורי הגישה שלכם להנפיק אישור גישה קצר מועד לשכפול עבור הזהות המופיעה בתביעת act של הטוקן. המשתנה CLAUDE_RUNNER_CLAUDE_BIN אינו מוגדר בסביבת הוו checkout, ולכן תת-הפקודה decode-token אינה זמינה כאן. נסיגה לכל אימות git שכבר קיים במארח, כגון SSH agent, מסייע אישורי גישה (credential helper), או קובץ .netrc, היא גם אפשרות.

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

  • מאגר שההפעלה דוחפת אליו תוצאות: הרנר מכשיל את ההפעלה, ובמקרה של יציאה עם קוד שאינו אפס הוא מציג למשתמש את סוף הפלט של stderr מהסקריפט.
  • מאגר שההפעלה קוראת ממנו בלבד, כגון מאגר שנוסף להפעלה פועלת: הרנר רושם שורת [runner:warn] ביומן עם פרטי הכישלון, מפרסם שלב Skipped בהפעלה, מסיר את מה שהוו השאיר בנתיב ה-checkout, וממשיך עם שאר המאגרים. כאשר הרנר אינו יכול להסיר את הנתיב באופן מיידי, הוא מנסה שוב את ההסרה בסיום ההפעלה. אם הדילוג מותיר את ההפעלה ללא מאגרים כלל, הרנר מכשיל את ההפעלה בכל מקרה.

לפני גרסה v2.1.228, הרנר הכשיל את ההפעלה בעת כישלון וו עבור כל מאגר שהוא, כך שמאגר לקריאה בלבד שהוו לא הצליח לשרת הכשיל את ההפעלה שוב בכל רנר חדש שההפעלה חודשה בו.

הרנר מסיר את נתיב ה-checkout לאחר סיום ההפעלה.

#post-session

רץ פעם אחת בכל הפעלה, לאחר שתהליך הבן של Claude Code הסתיים ולפני שהרנר מפרק את סביבת העבודה. וו זה הוא ההזדמנות היחידה שלכם לשמור עבודה שלא בוצע לה commit: כאשר הדגל --capacity מוגדר ליותר מאחד, הרנר מוחק את עצי העבודה (worktrees) של ההפעלה מיד לאחר שהוו מסיים את ריצתו, ובערך --capacity 1 השכפול הקנוני (canonical clone) שנעשה בו שימוש חוזר מאופס לחלוטין (hard-reset) בעת תחילת ההפעלה הבאה, כך ששינויים במעקב שלא בוצע להם commit אינם שורדים באף אחד מהמסלולים. שימושים אופייניים הם דחיפת ענף תמונת מצב (snapshot branch) של שינויים ללא commit, ארכוב יומנים, או שידור אירוע סיום הפעלה למערכות שלכם.

הוו מופעל בכל סיום הפעלה שבה נוצר תהליך בן, ללא קשר לסיבה. ערכי CLAUDE_RUNNER_EXIT_REASON להלן מפרטים את המקרים. הוא אינו יכול לפעול כאשר הרנר מסיים את פעולתו בפתאומיות, כגון הפקעת מכונה וירטואלית (VM preemption) או הפסקת חשמל. אם אתם זקוקים להבטחות מפני סיום פתאומי, בצעו תמונת מצב תקופתית מתוך ההפעלה באמצעות וו PostToolUse של Claude Code במקום זאת. הרנר מגדיר:

משתנהתיאור
CLAUDE_RUNNER_SESSION_IDמזהה ההפעלה במבנה עם קידומת session_...
CLAUDE_RUNNER_SESSION_UUIDאותו מזהה הפעלה במבנה UUID תקני
CLAUDE_RUNNER_EXIT_REASONכיצד ההפעלה הסתיימה, ראו את הערכים מתחת לטבלה
CLAUDE_RUNNER_WORKSPACE_PATHSנתיבים מוחלטים של עצי העבודה של ההפעלה, מופרדים בנקודתיים. ריק עבור הפעלות ללא מאגרים.
CLAUDE_RUNNER_DEBUG_LOG_PATHנתיב ליומן ניפוי השגיאות (debug log) של ההפעלה, שנמצא עדיין על הדיסק בזמן שהוו רץ
CLAUDE_RUNNER_API_BASE_URLכתובת ה-URL הבסיסית של API של Anthropic עבור קריאות בהיקף ההפעלה
CLAUDE_RUNNER_CLIENT_PLATFORMממשק הלקוח שיצר את ההפעלה, כגון web_claude_ai, desktop_app, או ios. אינו מוגדר כאשר להפעלה אין ממשק מתועד או מוכר.
CLAUDE_CODE_SESSION_ACCESS_TOKENטוקן הגישה של ההפעלה, עבור קריאות API בהיקף ההפעלה

המשתנה CLAUDE_RUNNER_EXIT_REASON מקבל אחד מארבעה ערכים:

  • completed: יציאה נקייה, כולל הפעלה שאורכבה או נמחקה בעוד תהליך הבן עדיין מחובר.
  • failed: קריסה של תהליך הבן או כשל בהגדרה לאחר היצירה.
  • interrupted: שחרור עקב חוסר פעילות, חריגה מזמן ההפעלה, ביטול הקצאה מהשרת, ריקון (drain), או עצירה כפויה על ידי מנגנון watchdog.
  • abandoned: שמור להפעלות שרנר אחר לקח עליהן בעלות. הוו אינו מופעל כרגע במקרה זה.

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

קוד היציאה של הוו לעולם אינו משפיע על תוצאת ההפעלה. כשל נרשם ביומן וזוכה להתעלמות. הרנר ממתין עד --post-session-hook-timeout-sec, 60 שניות כברירת מחדל, בכל סיום הפעלה כולל בעת כיבוי הרנר. דוגמה זו שומרת עבודה שלא בוצע לה commit לתוך ענף חילוץ (rescue branch):

#!/usr/bin/env bash
set -u
IFS=':'
# Pin config the session could have planted in the checkout's .git/config:
# -c overrides beat repo-local settings, blocking session-written fsmonitor,
# hook-path, and gpg-program config from executing code with the hook's
# privileges. Repo-local credential.helper, core.sshCommand, and pushurl
# still apply; if the hook holds credentials the session didn't, pin the
# push URL and helper too (see the note below the script).
g() { git -c core.fsmonitor=false -c core.hooksPath=/dev/null \
        -c commit.gpgsign=false "$@"; }
for ws in $CLAUDE_RUNNER_WORKSPACE_PATHS; do
  cd "$ws" 2>/dev/null || continue
  [ -z "$(g status --porcelain 2>/dev/null)" ] && continue
  g add -A
  g commit -q -m "runner snapshot: $CLAUDE_RUNNER_SESSION_ID ($CLAUDE_RUNNER_EXIT_REASON)" || continue
  g push -q origin "HEAD:refs/heads/rescue/$CLAUDE_RUNNER_SESSION_ID" || true
done

הוו מבצע push באמצעות אישורי הגישה של git שזמינים בסביבה שלו במארח הרנר. תחת מדיניות אי החזקת אישורי גישה ב-image, כולל כאשר ה-clone המובנה עובר דרך פרוקסי ה-git של Anthropic, אין אישורי גישה כאלה, לכן יש להנפיק אישור גישה קצר מועד ל-push בתוך הוו לפני ביצוע ה-push: החליפו את טוקן ההפעלה שהוו מקבל ב-CLAUDE_CODE_SESSION_ACCESS_TOKEN מול שירות הטוקנים שלכם, תוך אימותו כפי שמתואר באימות זהות הפעלה. כאשר הוו מחזיק באישור גישה שלא היה קיים בהפעלה, קבעו בנוסף לאן הוא דוחף: החליפו את origin בכתובת URL שסופקה על ידי המפעיל והעבירו את הפרמטר -c credential.helper= בתוספת מסייע אישורים משלכם, כך שהגדרות מקומיות במאגר שההפעלה כתבה לא יוכלו לנתב מחדש את הדחיפה המאומתת.

#תזמון הוו כאשר הרנר משחרר הפעלה

הפעלה ששוחררה יכולה להתחדש ברנר אחר. ברנר בגרסה v2.1.236 ומעלה, הפעולה שההפעלה ביצעה בעת השחרור קובעת האם היא יכולה להתחדש לפני שוו זה מסיים לפעול:

  • מצב סרק לאחר תור (turn), או חריגה מזמן ההפעלה הראשונית: הרנר עוצר את תהליך הבן ומריץ וו זה עד לסיומו. רק לאחר מכן הוא משחרר את ההפעלה. הודעת משתמש שנשלחת בזמן שהוו רץ אינה יכולה לחדש את ההפעלה ברנר אחר לפני שהוו מסיים.
  • המתנה למענה של המשתמש לשאלה, כגון בקשת הרשאה: הרנר משחרר תחילה את ההפעלה, ולאחר מכן מריץ וו זה. הודעת משתמש שנשלחת בזמן שהוו רץ יכולה לחדש את ההפעלה ברנר אחר לפני שהוו מסיים.

שחרור בזמן המוגדר על ידי --retire-at פועל לפי שני המסלולים הללו. במהלך ריקון הדרגתי עקב אות SIGTERM, הרנר מחזיק בחכירת ההפעלה (lease) עד שהוו מסיים, ראו תזמון כיבוי. לפני גרסה v2.1.236, הרנר שחרר תחילה את ההפעלה ולאחר מכן הריץ וו זה בשני המסלולים.

#command

רץ פעם אחת בכל הפעלה לאחר שלב ה-checkout, במקום יצירת תהליך הבן המובנית. הוו מקבל את אותה הסביבה כמו סקריפט עוטף ועליו לבצע exec לתוך "$CLAUDE_RUNNER_CLAUDE_BIN" באותו האופן. השתמשו בוו command כדי לרכז את כל ההתאמות האישיות בספריית ווים אחת. השתמשו ב---exec-path כאשר העוטף ממוקם במקום אחר. אם --exec-path מוגדר גם כן, הדגל מקבל עדיפות ומתעלמים מוו ה-command.

בצעו תמיד exec לקובץ הבינארי של הרנר עצמו במקום ל-claude שנמצא לפי ה-PATH, אחרת אתם עוקפים את קיבוע הגרסה (version pinning).

#רנרים לפי דרישה (On-demand runners)

במקום להריץ צי קבוע של רנרים, תוכלו להפעיל רנר אחד לכל הפעלה. מנהל התזמור (orchestrator) הוא תת-פקודה נפרדת ונטולת מצב (stateless) הדוגמת את Anthropic עבור בקשות יצירה (spawn requests), אחת לכל הפעלה שממתינה בתור כשאין רנר זמין, ומריצה את וו ה-spawn-runner שלכם עבור כל בקשה. הוו שלכם שולח משימה לפלטפורמה שלכם: משימת Kubernetes Job, מופע EC2, או Nomad dispatch.

רנרים לפי דרישה משפרים את הגיינת אישורי הגישה. בצי קבוע, סוד הסביבה (environment secret) נמצא בכל מארח של רנר, שהוא אותו מארח שמריץ את הפעלות המשתמשים. בעזרת מנהל התזמור, סוד הסביבה נשאר אך ורק במארח של מנהל התזמור, שלעולם אינו מריץ קוד משתמש. כל רנר שנוצר מקבל פקודת עבודה (work order) לשימוש חד פעמי שרושמת רנר אחד בדיוק ולאחר מכן פג תוקפה.

כדי להפעיל את מנהל התזמור, העבירו את סוד הסביבה ואת ספריית הווים המכילה סקריפט spawn-runner בר הפעלה:

claude self-hosted-runner orchestrator \
  --environment-secret-file /etc/claude/environment-secret \
  --hooks-dir /etc/claude/hooks

מנהל התזמור אינו שומר מצב בין דגימות, לכן תוכלו להריץ שני עותקים (replicas) או יותר מול אותה הסביבה לצורכי זמינות גבוהה. כל בקשת יצירה נתבעת בצד השרת על ידי עותק אחד בדיוק. כל העותקים חייבים להשתמש באותו ערך עבור --expected-spawn-seconds, ראו את חוזה הוו.

#הוו spawn-runner

מנהל התזמור מריץ את ${hooks-dir}/spawn-runner פעם אחת לכל בקשת יצירה. הוו חייב להגיש את העבודה באופן אסינכרוני, מבלי להמתין לעליית הרנר, ולחזור בתוך --hook-timeout, 60 שניות כברירת מחדל. הוו מקבל:

משתנהתיאור
CLAUDE_RUNNER_WORK_ORDER_FILEנתיב לקובץ זמני המכיל את ה-JWT החתום של פקודת העבודה שאיתו הרנר החדש נרשם. הקובץ נמחק לאחר יציאת הוו. אין לרשום את תוכן הקובץ ביומן.
CLAUDE_RUNNER_ORDER_IDמפתח אידמפוטנטיות אטום, ייחודי לכל בקשת יצירה ובטוח לשימוש כשמות משאבים ב-Kubernetes. השתמשו בו כמפתח למניעת כפילויות (dedup key) בספק ההקצאה שלכם.
CLAUDE_RUNNER_SESSION_IDההפעלה שבקשה זו מיועדת עבורה. ריק עבור בקשות חימום מראש (pre-warming), המעלות רנר בכוננות לפני הפעלה ספציפית כאשר --min-idle מוגדר, לכן אל תניחו שהמשתנה מוגדר.
CLAUDE_RUNNER_SESSION_UUIDאותו מזהה הפעלה במבנה UUID תקני. ריק עבור בקשות חימום מראש.
CLAUDE_RUNNER_ATTEMPTמספר בקשות היצירה שהיו להפעלה זו. 0 עבור בקשות חימום מראש.
CLAUDE_RUNNER_ORDER_SERVER_TIMEזמן השרת מתוך כותרת ה-HTTP Date של תשובת הדגימה. כאשר הוו מאמת את שדה exp ב-JWT של פקודת העבודה, השוו מול ערך זה במקום מול השעון המקומי כדי להתמודד עם הפרשי זמנים (skew). ריק כאשר שער הגישה השמיט את הכותרת.
CLAUDE_RUNNER_POOL_IDהמזהה של הסביבה שהרנר החדש אמור להצטרף אליה, במבנה ccpool_...
CLAUDE_RUNNER_ACCOUNT_IDמזהה מתויג של החשבון שהכניס את ההפעלה לתור, עבור ניתוב לפי חשבון, מכסות, או חיוב חוזר (chargeback). ריק כאשר אינו זמין, ותמיד ריק עבור הפעלות בערוץ Claude Tag, ששום חשבון אינו מכניס לתור.
CLAUDE_RUNNER_ACCOUNT_EMAILכתובת האימייל של החשבון שהכניס את ההפעלה לתור. ריק כאשר אינו זמין. התייחסו לאימייל כמידע המזהה אדם באופן אישי (PII) ואל תתעדו אותו ביומן.
CLAUDE_RUNNER_PRIMARY_REPO_URLכתובת ה-URL של מקור ה-git הראשון של ההפעלה, לצורך ניתוב לרנר שהמאגר כבר חומם בו מראש. ריק כאשר להפעלה אין מקורות git.
CLAUDE_RUNNER_PRIMARY_REPO_REVISIONהגרסה (revision) של מקור ה-git הראשון של ההפעלה: ענף, SHA, או תגית. ריק כאשר לא צוין.
CLAUDE_RUNNER_REPO_SOURCESמערך JSON של {url, revision} עבור כל מקורות ה-git של ההפעלה, עבור ווים המנתבים לפי מאגר משני. ריק כאשר אין מקורות.
CLAUDE_RUNNER_CORRELATION_IDמזהה הקורלציה שסופק בעת יצירת ההפעלה, המוחזר כדי שהוו יוכל למפות פקודת עבודה זו לבקשה שיצרה את ההפעלה. ריק כאשר אין מזהה כזה.
CLAUDE_RUNNER_CLIENT_PLATFORMממשק הלקוח שיצר את ההפעלה, כגון web_claude_ai, desktop_app, ios, או scheduled_trigger, לצורכי ניתוח נתוני שימוש. אינו מוגדר כאשר להפעלה אין ממשק מתועד או מוכר, וכן עבור בקשות חימום מראש. בדקו אותו באמצעות [ -n "${CLAUDE_RUNNER_CLIENT_PLATFORM:-}" ], שנשאר בטוח תחת set -u.

הרנר שנוצר נרשם באמצעות פקודת העבודה במקום סוד הסביבה:

  • הפעילו אותו עם פקודת העבודה: הפנו את הדגל --environment-secret-file לקובץ המכיל את ה-JWT של פקודת העבודה, או הגדירו את SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET לערך ה-JWT.
  • העתיקו את ה-JWT לפני שהוו מסיים: מנהל התזמור מוחק את קובץ פקודת העבודה לאחר שהוו מסיים, לכן העתיקו את ה-JWT לתוך עומס העבודה שאתם מגישים, כגון Kubernetes Secret בתוך ה-Job שנוצר, במקום להעביר את נתיב הקובץ.
  • השתמשו ב---capacity 1 ברנרים שנוצרו לפי דרישה: פקודת עבודה הקשורה להפעלה רושמת בדיוק רנר אחד שמשויך להפעלה זו, ולכן קיבולת גבוהה יותר מוסיפה חריצים (slots) שלעולם אינם מקבלים עבודה, והרנר רושם אזהרה בעת ההפעלה.
  • פקודות עבודה לחימום מראש נרשמות ללא שיוך: רנר הכוננות אינו משויך להפעלה ספציפית ותובע עבודה הממתינה בתור בדיוק כמו רנר בצי קבוע.

לחוזה יש ארבעה כללים שאינם תלויים בספק התשתית:

  1. פעלו באופן אידמפוטנטי לפי CLAUDE_RUNNER_ORDER_ID. מסירה חוזרת של אותה בקשה חייבת להעלות לכל היותר רנר אחד. גזרו שם משאב דטרמיניסטי מהמזהה ואפשרו לפלטפורמה שלכם לדחות את הכפילות.
  2. אל תנסו שוב את עומס העבודה. מזהה פקודה אחד פירושו לכל היותר עומס עבודה אחד שנוצר. אם הרנר לעולם אינו נרשם, Anthropic מבקשת שוב עם מזהה פקודה חדש לאחר --expected-spawn-seconds.
  3. השתמשו בחוזה קודי היציאה. קוד יציאה 0 פירושו שהעבודה הוגשה בהצלחה. קוד יציאה 1 פירושו כשל הניתן לניסיון חוזר (retryable), ההפעלה נסוגה להמתנה ומוצעת מחדש. קוד יציאה 2 ומעלה פירושו כשל שאינו ניתן לניסיון חוזר, ההפעלה נחסמת מיצירה חוזרת עד אשר בעלים (Owner) יבחר ב-Retry בלשונית Activity של הסביבה. ביציאה עם קוד שאינו אפס, סוף הפלט של stderr מהוו מופיע שם כסיבת הכישלון, לכן כתבו שגיאה שניתן לפעול לפיה ל-stderr ולעולם אל תכתבו סודות. עבור בקשת חימום מראש אין הפעלה שניתן להכשיל: מנהל התזמור רושם יציאה שאינה אפס באופן מקומי בלבד, והשרת מבקש מחדש את היצירה לאחר תום תקופת החכירה.
  4. הגדירו את --expected-spawn-seconds לפחות לזמן העלייה ב-p99 שלכם. זוהי תקופת החכירה בצד השרת. כל עותקי מנהל התזמור חייבים להשתמש באותו הערך.

כל מה שהוו כותב ל-stdout או ל-stderr מופיע ביומן של מנהל התזמור כאשר אישורי גישה מצונזרים באופן אוטומטי. אם הפעלות נשארות בתור, בדקו את גוף התשובה של /healthz במנהל התזמור עבור ספירת התורים, ולאחר מכן פתחו את לשונית Activity של הסביבה שלכם בדף הניהול Cloud environments: הרחיבו שם הפעלה שנכשלה כדי לראות את שגיאת היצירה שלה, ובחרו ב-Retry כדי לבקש אותה שוב.

#שרתי MCP

כדי להפוך שרתי MCP לזמינים בכל הפעלה, הוסיפו אותם בעת בניית ה-image באמצעות אותה פקודת claude mcp add המשמשת בהתקנה שולחנית. אם הרנר שלכם הוא תהליך עצמאי ולא מכולה (container), הריצו את אותה הפקודה כמשתמש של הרנר במארח, ולאחר מכן הפעילו מחדש את הרנר: הוא קורא את תצורת המארח פעם אחת בעת ההפעלה. הדגל --scope user הוא חובה, שכן היקף מקומי (local scope) כברירת מחדל כותב תחת מפתח ייעודי לספרייה שהרנר אינו מזין לתוך הפעלות. לדוגמה, ב-Dockerfile שלכם:

RUN claude mcp add --scope user sidecar -- /usr/local/bin/mcp-sidecar
RUN claude mcp add --scope user --transport http internal http://mcp-gateway.svc.cluster.local:8080

הרנר לוכד תמונת מצב של תצורת המארח פעם אחת בעת ההפעלה. תמונת המצב לוכדת את המפתח mcpServers מתוך קובץ .claude.json של המארח, שנמצא לצד ~/.claude/ ולא בתוכו, והרנר מזין רק מפתח זה לתוך התצורה המבודדת של כל הפעלה. מצב החשבון והיסטוריית הפרויקטים מושמטים. כדי לוודא שהשרתים הגיעו להפעלות, התחילו הפעלה בסביבה ובקשו מ-Claude לרשום את כלי ה-MCP שלו. הרנר גם רושם אזהרה בעת ההפעלה עבור כל רשומה שנלכדה שה-type שלה אינו מזוהה ומשמיט את הרשומה, כך שתוכלו לראות מדוע שרת זה חסר בהפעלות. כאשר SELF_HOSTED_RUNNER_HOST_CONFIG_DIR מוגדר, הרנר קורא את .claude.json מספרייה זו במקום זאת, כך שהפניית המשתנה לספרייה ריקה משביתה גם את הזנת ה-MCP.

שני מקורות נוספים פועלים גם הם:

  • קובץ ה-MCP המנוהל (managed MCP file) ברמת הארגון (enterprise-scope) בנתיב המערכת הסטנדרטי שלו: /etc/claude-code/managed-mcp.json במארחי רנר של Linux, ו-/Library/Application Support/ClaudeCode/managed-mcp.json במארחי macOS. השתמשו בו עבור ציים נעולים שבהם מותר לטעון רק שרתים המאושרים על ידי מנהל מערכת. ראו שליטה בלעדית באמצעות managed-mcp.json עבור כללי קדימות. כאשר קובץ זה קיים במארח הרנר, Claude Code מדלג על שרתי ה-MCP שמישור הבקרה של Anthropic מוסר להפעלה, כולל מחברי claude.ai (מחברי connectors), ומציין אותם באזהרה ב-stderr של תהליך הבן של ההפעלה, שהרנר רושם ברמת יומן debug. לפני גרסה v2.1.229, הפעלות אלה יצאו בעת ההפעלה עם השגיאה You cannot dynamically configure MCP servers when an enterprise MCP config is present.
  • <repo>/.mcp.json: ברמת הפרויקט (project scope). בצעו commit לקובץ לתוך מאגר הקוד. השרתים שלו מאושרים אוטומטית בהפעלות ענן.

כאשר אספקת מחברים (connectors) מופעלת בארגון שלכם, מישור הבקרה של Anthropic מספק את המחברים שהגדרתם ב-claude.ai להפעלות שנוצרו באופן אינטראקטיבי דרך תצורת MCP המסופקת על ידי השרת, המנותבת דרך api.anthropic.com. הפעלות שנוצרו באופן תכנותי, כגון שילוח דרך ה-CLI, אינן מקבלות אספקת מחברים. ספקו להן שרתי MCP דרך תמונת המצב של המארח, קובץ ה-MCP המנוהל (managed MCP file), או <repo>/.mcp.json. טוקן ה-OAuth של תהליך הבן אינו נושא הרשאה (scope) למשיכת מחברים ישירות, ולכן תהליך הבן אינו מנסה לבצע משיכה זו בעצמו, האספקה מונעת על ידי השרת.

הקבצים settings.json ו-managed-settings.json אינם נושאים הגדרות של שרתי MCP. אין שדה mcpServers ברמה העליונה בסכמת ההגדרות.

הפעלות יורשות את סביבת הרנר, לכן הגדירו בה את ENABLE_TOOL_SEARCH כדי לשלוט בחיפוש כלי MCP עבור כל הפעלה שרנר מפעיל. דף ה-MCP מפרט את הערכים האפשריים.

#תזכורת להפעלות לדחוף את עבודתן (Push)

הפעלות המאוחסנות על ידי Anthropic מריצות וו Stop, וו Claude Code שרץ כאשר Claude מסיים להשיב, אשר מנחה את Claude לבצע commit ו-push לעבודתו. הרנר אינו מתקין וו כזה. בלעדיו, הפעלה שמסתיימת עם שינויים שלא בוצע להם commit משאירה את העבודה הזו על הדיסק של הרנר בלבד, והכפתור Create PR ב-claude.ai/code נשאר לא פעיל עד שהענף קיים בשרת המרוחק.

ליישום הייחוס להלן יש שני חלקים. מזגו את בלוק ההגדרות לתוך ~/.claude/settings.json במארח הרנר, שהרנר מזין לתוך כל הפעלה, ושמרו את הסקריפט כ-~/.claude/hooks/stop-hook-nudge.sh במארח הרנר והפכו אותו לבר-ביצוע (executable):

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "timeout": 10,
            "command": "\"$CLAUDE_CONFIG_DIR/hooks/stop-hook-nudge.sh\""
          }
        ]
      }
    ]
  }
}
#!/bin/sh
# Stop-hook reference implementation for self-hosted runners.
#
# Nudges Claude once per turn if the project directory has uncommitted
# changes OR unpushed commits, so work isn't lost when an idle session
# is released and so the "Create PR" button on claude.ai/code lights up.
#
# Runner-level (no repo changes): drop this file at ~/.claude/hooks/ on
# the runner host and merge the accompanying Stop-hook settings block
# into ~/.claude/settings.json: the runner seeds both into every session.
# Repo-level alternative: commit to <repo>/.claude/hooks/ and change the
# settings.json command path to $CLAUDE_PROJECT_DIR/.claude/hooks/.
#
# stdin: hook JSON payload (see https://code.claude.com/docs/en/hooks)
# stdout: {"decision":"block","reason":"..."} to nudge, or nothing to allow stop.

# Re-entry guard: the harness sets stop_hook_active=true when re-invoking
# the Stop hook after a block. Bail so we only nudge once per turn. The
# harness emits compact JSON (no space after the colon), which this
# pattern relies on; use jq if you need a whitespace-tolerant check.
in=$(cat)
case "$in" in *'"stop_hook_active":true'*) exit 0 ;; esac

d="$CLAUDE_PROJECT_DIR"

# Not a git repo -> nothing to nudge.
git -C "$d" rev-parse --git-dir >/dev/null 2>&1 || exit 0

# No remote -> "push to the remote" is unsatisfiable; bail.
[ -z "$(git -C "$d" remote 2>/dev/null)" ] && exit 0

# Uncommitted changes (staged, unstaged, or untracked). Exclude .claude/
# entirely: operator-seeded settings and CLI-written runtime state
# (scheduler lock, worktrees, routine state) live there and neither is
# "uncommitted work" the model needs to push.
s=$(git -C "$d" status --porcelain -- . ':(exclude).claude/' 2>/dev/null)
if [ -n "$s" ]; then
  printf '{"decision":"block","reason":"There are uncommitted changes in the repository. Please commit and push these changes to the remote branch."}'
  exit 0
fi

# Unpushed commits. Count commits on HEAD not reachable from any
# remote-tracking ref or FETCH_HEAD. This works uniformly for:
#   - init+fetch checkouts (runner default: only FETCH_HEAD exists)
#   - clone-based checkouts (origin/* exist)
#   - the runner default: the child starts on the session's outcome
#     branch, which the runner creates after checkout
#   - detached HEAD, when a custom setup skips that branch creation
# With no reference point at all (never fetched), stay silent rather
# than false-positive on a read-only turn.
base=""
git -C "$d" rev-parse --verify -q FETCH_HEAD >/dev/null && base="FETCH_HEAD"
if [ -z "$base" ] && [ -z "$(git -C "$d" for-each-ref --count=1 refs/remotes/origin 2>/dev/null)" ]; then
  exit 0
fi
# shellcheck disable=SC2086  
# $base is either "" or "FETCH_HEAD", intentional word-split
unpushed=$(git -C "$d" rev-list HEAD --not $base --remotes=origin --count 2>/dev/null) || unpushed=0
if [ "$unpushed" -gt 0 ]; then
  branch=$(git -C "$d" symbolic-ref --short -q HEAD)
  if [ -n "$branch" ]; then
    
# $branch is attacker-influenced: git-check-ref-format(1) allows `"`
    
# in ref names. `\` is forbidden (rule 10) but escaped anyway as cheap
    
# defense-in-depth.
    
# Escape JSON metacharacters before interpolating into the hand-built
    
# payload so a branch like x","continue":false can't inject keys into
    
# the hook-output JSON the harness parses. $unpushed is safe: the
    
# -gt guard above rejects anything that isn't a plain integer.
    branch_esc=$(printf '%s' "$branch" | sed 's/\\/\\\\/g; s/"/\\"/g')
    printf '{"decision":"block","reason":"There are %s unpushed commit(s) on branch '\''%s'\''. Please push these changes to the remote repository."}' "$unpushed" "$branch_esc"
  else
    printf '{"decision":"block","reason":"There are %s unpushed commit(s) on a detached HEAD. Please create a branch and push it to the remote repository."}' "$unpushed"
  fi
  exit 0
fi

exit 0

הוו מנחה את Claude לבצע commit ו-push לפני סיום ההפעלה, ושומר על שתיקה כאשר הספרייה אינה מאגר git או שאין לה שרת מרוחק (remote).

#הרשאות ואישור כלים

להפעלה באירוח עצמי אין מסוף (terminal) מחובר, ולכן בקשת הרשאה שלא נענתה מעכבת את התור עד שהמשתמש מגיב בממשק. מישור הבקרה של Anthropic שולח את רשימת הכלים וכללי ההרשאות של כל הפעלה יחד עם מטען העבודה. תצורת ברירת המחדל מאשרת מראש קריאות שגרתיות לכלים, כולל Bash, והפעלות ענן מאשרות מראש עריכות קבצים ללא תלות במצב. קריאה ששום כלל אינו מאשר מראש מקפיצה בקשה דרך ממשק המשתמש של ההפעלה.

הערה: קבעו מצב אוטומטי (auto mode) אך ורק בסביבה שמכולות ההפעלה שלה פועלות עם חסימת ברירת מחדל לתעבורת רשת יוצאת (default-deny network egress) ושאר סעיף הקשחת האבטחה מיושם בה. קריאות שגרתיות לכלים, כולל בקשות רשת דרך Bash, רצות ללא מגע יד אדם הן בערכת הכלים המאושרת מראש כברירת מחדל והן במצב אוטומטי, ולכן גבולות הרשת הם אלו שמגבילים לאן קריאות אלו יכולות להגיע.

כדי לצמצם את בקשות ההרשאה למינימום ללא קשר למה שמישור הבקרה שולח, קבעו מצב אוטומטי (auto mode) מתוך הסקריפט העוטף שלכם או מתוך וו command. מצב אוטומטי מאפשר להפעלות לפעול ללא בקשות הרשאה שגרתיות: מודל סיווג נפרד בודק פעולות לפני הפעלתן וחוסם את אלו שהוא דוחה, וכללי בקשה מפורשים (ask rules) עדיין מחייבים בקשת אישור. דף מצבי ההרשאה מפרט מה בודק המסווג. הרנר משרשר דגלים שחושבו בשרת לפני הפעלת העוטף, ועבור דגלים בעלי ערך יחיד כגון --permission-mode המנתח מכבד את המופע האחרון, כך שדגל שתוסיפו אחרי "$@" דורס את הערך שנשלח מהשרת:

#!/bin/bash
exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" --permission-mode auto

כדי לאשר מראש כלים ספציפיים במקום זאת, הוסיפו את הדגל --allowed-tools עם הכללים שלכם, לדוגמה --allowed-tools "Bash(bazel *) Bash(yarn *) mcp__internal__*". דגלים המקבלים רשימות, כגון --allowed-tools ו---disallowed-tools, מצטברים לאורך כל המופעים שלהם במקום להידרס, כך שהכללים שלכם מוחלים בנוסף לכל הכללים שמישור הבקרה שולח. כדי להגביל, הוסיפו את --disallowed-tools, אשר שולל כלים גם אם כלל אחר מתיר אותם.

#כיצד מורכבת תצורת ההפעלה

הרנר מעניק לכל הפעלה ספריית תצורה משלה, המוזנת מתוך תמונת מצב בזיכרון של ~/.claude/ במארח שהרנר לוכד פעם אחת בעת ההפעלה: הקבצים settings.json, CLAUDE.md, ווים, סוכנים, פקודות וכישורים (skills) ב-image של הרנר שלכם מוחלים על כל הפעלה כקו הבסיס ברמת המשתמש. מכיוון שתמונת המצב נלקחת בעת ההפעלה, שינויי תצורה במארח פעיל נכנסים לתוקף רק לאחר הפעלה מחדש של הרנר. הגדירו את SELF_HOSTED_RUNNER_HOST_CONFIG_DIR כדי להזין מנתיב אחר, או הפנו אותו לספרייה ריקה כדי להשבית את ההזנה.

קובץ .claude/settings.json שנשמר במאגר הקוד נוסף כשכבה מעל כהגדרות פרויקט. הפעלות קוראות גם את הקובץ managed-settings.json מנתיב המערכת הסטנדרטי ב-image של הרנר שלכם. השאלה האם המפתחות שלו מוחלים לצד הגדרות מנוהלות מהשרת נקבעת לפי האופן שבו Claude Code משלב מקורות מנוהלים: כברירת מחדל, כאשר הארגון שלכם מספק מפתחות כלשהם המנוהלים מהשרת, הפעלות מתעלמות מהקובץ שב-image של הרנר, למעט המפתחות ש-Claude Code קורא מכל מקור מנהל מערכת, כגון בלוק env, נעילות ה-sandbox, נתיבי הקבצים הבינאריים של ה-sandbox, ו-forceRemoteSettingsRefresh. ראו סדר קדימויות של הגדרות.

כאשר מישור הבקרה של Anthropic מספק להפעלה ווי Claude Code, הרנר מתקין אותם לצד התצורה שלכם, ולא דורס אותה. דורש את Claude Code בגרסה v2.1.229 ומעלה.

  • היכן הם נשמרים: הרנר כותב כל סקריפט של וו שסופק לתוך תת-ספרייה שמורה hooks/.ccr-launcher/ של ספריית התצורה של ההפעלה ורושם את הסקריפטים בקובץ הגדרות נפרד שהוא מעביר להפעלה באמצעות --settings, תוך השארת הקובץ settings.json שהוזן והסקריפטים שלכם ב-hooks/<name> ללא שינוי. הרנר יוצר מחדש את תת-הספרייה השמורה עבור כל הפעלה ואינו מזין תוכן מארח מ-~/.claude/hooks/.ccr-launcher/ לתוך הפעלות.
  • מי מחבר אותם: מישור הבקרה ממלא את הסקריפטים מתוך קבועים קבועים מראש בפריסה שלו, לעולם לא מתוך קלט של ההפעלה או צד שלישי.
  • מה עדיין שולט בהם: ווים שנמסרו באמצעות --settings נכנסים לתצורת הווים הממוזגת הרגילה, ולא לשכבה המנוהלת, כך שההגדרות המנוהלות שלכם עדיין חלות עליהם. ההגדרה disableAllHooks משביתה אותם, והם אינם נמנים עם הקטגוריות ש-allowManagedHooksOnly שומרת כטעונות.

#כללי הרשאות שנשמרו במאגר הקוד (Repository-committed)

אל תציבו רשומה חשופה של "Edit", "Write", או "NotebookEdit" בתוך permissions.allow שנשמר במאגר הקוד. כלל כלי קבצים חשוף תואם לכלי ללא תלות בנתיב, ומעניק הרשאות כתיבה בכל מקום במארח ולא רק בסביבת העבודה, כך שמנגנון ההגבלה של היקף הכתיבה של הרנר מסמן את ההפעלה כחשודה. עם הדגל --confine-repo-settings enforce הוא מסרב להפעיל את ההפעלה במקום לרשום ביומן ולהמשיך. ראו את סעיף הקשחת האבטחה.

מאגר קוד אינו זקוק לכלל עבור כלי קבצים כלל: הפעלות ענן מאשרות מראש עריכות קבצים ללא תלות במצב. אם אתם שומרים כלל במאגר, הגבילו את ההיקף שלו לסביבת העבודה, כגון "Edit(/**)". לוכסן בודד בהתחלה הוא יחסי לשורש הפרויקט, שהוא סביבת העבודה של ההפעלה. כללי כלי קבצים חשופים מותרים בקובץ settings.json של המפעיל ברמת המארח, מכיוון שקובץ זה אינו נשמר במאגר הקוד.

הגדרה של defaultMode כ-auto מכובדת רק מקובץ ההגדרות של ה-image כולו או מקובץ ההגדרות ברמת המשתמש, כך שמאגר קוד שעבר checkout אינו יכול להעניק לעצמו מצב אוטומטי. לגבי המצבים שהפעלות ענן מקבלות ולתחביר הכללים המלא, ראו מצבי הרשאה.

#מה הלאה