SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-23

إعداد شريط حالة Claude Code على VPS

اعرض اسم الخادم والمسار وفرع Git والنموذج أسفل الموجه عبر statusLine، لتعرف الخادم الصحيح قبل تنفيذ الأوامر على جلسات SSH المتعددة.

ما الذي يعرضه شريط الحالة في Claude Code

شريط الحالة في Claude Code هو سطر أسفل موجه الأوامر يعرض ناتج script تكتبه أنت. أضف كتلة statusLine إلى settings.json، وحدد فيها command. يشغّل Claude Code ذلك command، ويرسل حالة الجلسة إليه بتنسيق JSON عبر الإدخال القياسي، ثم يطبع كل ما يكتبه command إلى الإخراج القياسي.

هذا هو العقد الكامل. يقرأ script الخاص بك JSON من stdin ويطبع نصاً إلى stdout. يعمل script على جهازك، ولا يُرسل أي شيء يطبعه إلى النموذج، لذلك لا يستهلك أي tokens.

على laptop يحتوي على project واحد، يكون هذا مجرد تنسيق. أما على ثلاثة servers، فهو وسيلة أمان. تبدو كل جلسة Claude Code متطابقة في كل terminal، ولذلك قد تؤدي أربع نوافذ SSH بلا عناوين إلى تنفيذ migration على server الخطأ. ينهي statusline الذي يبدأ باسم hostname هذا النوع من الأخطاء.

موضع إعداد statusLine في settings.json

ضعه في إعدادات المستخدم ضمن ~/.claude/settings.json، ويُطبَّق ذلك على كل مشروع في الجهاز. تعمل إعدادات المشروع الموجودة في .claude/settings.json داخل المستودع أيضاً، وتكون لها الأولوية في ذلك المجلد.

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}

تكون type دائماً "command". وتُشغَّل قيمة command عبر shell، لذلك يمكن أن تكون مساراً إلى script أو أمراً عاديّاً. أثبت أن الربط يعمل قبل كتابة أي script:

{
  "statusLine": {
    "type": "command",
    "command": "hostname -s"
  }
}

شغّل Claude Code وأرسل رسالة واحدة. سيعرض الشريط الموجود أسفل prompt الآن اسم المضيف المختصر للخادم. إذا بقي فارغاً، فالمشكلة في الإعداد أو في مربع حوار الثقة، وليست في script. راجع «لماذا يبقى statusline فارغاً» أدناه.

توجد ثلاثة مفاتيح اختيارية اعتباراً من August 2026. يضيف padding مسافة أفقية بعدد الأحرف، وتكون قيمته الافتراضية 0. يعيد refreshInterval تشغيل الأمر كل N seconds بالإضافة إلى المشغلات العادية، بحد أدنى قدره 1. استخدمه فقط عندما يعرض السطر ساعة أو شيئاً يتغير أثناء بقاء الجلسة خاملة. يمنع hideVimModeIndicator عرض النص المضمّن -- INSERT -- عندما يعرض script الخاص بك وضع vim بالفعل.

ما البيانات التي يستقبلها script الخاص بـstatusline؟

لا تثق بقائمة حقول تقرؤها في أي مكان، بما في ذلك هذه الصفحة. التقط الكائن الفعلي الذي ترسله نسختك. اكتب script مؤقتاً يحفظ stdin في ملف:

cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.sh

وجّه statusLine.command إلى ذلك الملف، وابدأ جلسة، وأرسل رسالة واحدة. يقرأ الشريط captured. انظر الآن إلى ما وصل:

jq . /tmp/statusline-input.json

لديك البنية الدقيقة لإصدارك، ويمكنك تكرار ذلك في أي وقت يغيّر فيه تحديث ما شيئاً.

الأجزاء المستقرة، وفقاً للتوثيق في August 2026، هي كائنات متداخلة وليست مفاتيح مسطحة. يحتوي model على id وdisplay_name. ويحتوي workspace على current_dir وproject_dir: يحدد current_dir مكان الجلسة الآن، ويحدد project_dir المكان الذي بدأت فيه، ويختلف الاثنان بعد تغيير دليل العمل أثناء الجلسة. ويحمل cwd في المستوى الأعلى القيمة نفسها التي يحملها workspace.current_dir. ويحتوي context_window على أعداد الرموز بالإضافة إلى used_percentage المحسوبة مسبقاً. ويحتوي cost على total_cost_usd وعدادات المدة. ويبقى session_id ثابتاً طوال مدة الجلسة، ويكون فريداً بين الجلسات، وهذا مهم للتخزين المؤقت لاحقاً.

تحافظ ثلاث قواعد على عمل script بعد تغيّر المخطط.

بعض المفاتيح غير موجودة، وليست null. لا تظهر vim وagent وpr وworktree وeffort إلا عند تفعيل الميزة المطابقة. تؤدي قراءة .vim.mode باستخدام jq -r أثناء إيقاف vim mode إلى طباعة السلسلة الحرفية null، ويعرض شريطك null للقارئ. أضف // empty إلى كل selector، لكي تطبع المفاتيح المفقودة قيمة فارغة تماماً.

تكون بعض القيم null في البداية. تكون context_window.used_percentage وcontext_window.current_usage بقيمة null قبل أول استجابة من API، ويعود current_usage إلى null بعد /compact إلى أن تعيد المكالمة التالية تعبئته. لذلك يحتاج عرض نسبة السياق على الشريط إلى // 0، وإلا فسيقرأ null خلال الثواني الأولى من كل جلسة. قبل وضع هذا الرقم على شريط، من المفيد معرفة كيفية امتلاء نافذة السياق فعلياً.

فرع git غير موجود في JSON. لا يوجد حقل يعرضه. يأتي أي فرع يظهر على شريطك من تشغيل script للأمر git بنفسه.

برنامج statusline يتراجع بسلاسة بدلاً من التوقف

هذه هي النسخة الجاهزة للنسخ واللصق. تطبع اسم المضيف، ودليل العمل، وفرع git، واسم النموذج. يحتوي كل حقل على قيمة احتياطية، لذلك ينتج حتى كائن JSON فارغ سطراً قابلاً للاستخدام.

#!/bin/bash
# ~/.claude/statusline.sh
input=$(cat)

# Read one field. Prints nothing when the key is missing or null.
field() { printf '%s' "$input" | jq -r "$1 // empty" 2>/dev/null; }

HOST=$(hostname -s 2>/dev/null)
[ -z "$HOST" ] && HOST="host"

DIR=$(field '.workspace.current_dir')
[ -z "$DIR" ] && DIR=$(field '.cwd')
[ -z "$DIR" ] && DIR="$PWD"

MODEL=$(field '.model.display_name')
[ -z "$MODEL" ] && MODEL="claude"

SHORT="$DIR"
if [ -n "$HOME" ]; then
  case "$DIR" in
    "$HOME") SHORT="~" ;;
    "$HOME"/*) SHORT="~/${DIR#"$HOME"/}" ;;
  esac
fi

BRANCH=""
if git -C "$DIR" rev-parse --git-dir >/dev/null 2>&1; then
  BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
  [ -z "$BRANCH" ] && BRANCH="detached"
fi

CYAN=$'\033[36m'
YELLOW=$'\033[33m'
DIM=$'\033[2m'
RESET=$'\033[0m'

LINE="${CYAN}${HOST}${RESET} ${SHORT}"
[ -n "$BRANCH" ] && LINE="${LINE} ${YELLOW}${BRANCH}${RESET}"
LINE="${LINE} ${DIM}${MODEL}${RESET}"

printf '%s\n' "$LINE"

تمر كل قراءة عبر field، الذي يضيف // empty، لذلك ينتج المفتاح الذي أُعيدت تسميته أو حُذف سلسلة فارغة، ثم يوفّر السطر التالي قيمة افتراضية. يتراجع الدليل من workspace.current_dir إلى cwd ثم إلى $PWD. ويأتي الفرع من git -C "$DIR" بدلاً من استخدام git مجرداً، لذلك يطابق الفرع دائماً الدليل الذي يعرضه الشريط.

احفظ الملف، ثم اجعله قابلاً للتنفيذ:

chmod +x ~/.claude/statusline.sh

إذن التنفيذ ليس اختيارياً. يشغّل Claude Code الأمر عبر shell، لذلك يفشل البرنامج النصي الذي لا يحتوي على +x مع Permission denied، ولا ينتج stdout، ويبقى الصف فارغاً من دون ظهور أي خطأ.

يحلّل jq بيانات JSON من سطر الأوامر، ولا يكون مثبتاً على خادم Ubuntu جديد:

sudo apt update && sudo apt install -y jq

بعد ذلك، وجّه الإعداد إلى البرنامج النصي، باستخدام كتلة settings.json الأولى أعلاه.

اختبر البرنامج النصي قبل أن تثق به

شغّله يدوياً مرتين. أولاً باستخدام كائن جلسة عادي:

echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.sh

تحصل على اسم المضيف، ثم /srv/api، ثم Opus. لا يظهر أي فرع، لأن /srv/api على جهازك ليس مستودع git على الأرجح.

ثانياً، اختبر التدهور، وهو الاختبار الذي يتخطاه الناس عادةً:

echo '{}' | ~/.claude/statusline.sh

الكائن الفارغ هو أسوأ حالة يمكن أن يسلّمك إياها تغيير في المخطط. يظل السطر يطبع اسم المضيف، والدليل الحالي من $PWD، والكلمة claude في موضع اسم النموذج. لا يحدث أي تعطل، ولا تُطبع null. ينجح البرنامج النصي الذي يجتاز هذا الاختبار في التعامل مع إعادة تسمية حقل، لأن الحقل المُعاد تسميته والحقل المفقود يمثلان الحدث نفسه بالنسبة إلى البرنامج النصي.

ما ينبغي أن تراه

يُعرض سطر الحالة في صف مستقل فوق شارات التذييل المضمّنة، ولا يستبدلها. في الإعداد العامل، يتكوّن من صف واحد: اسم المضيف المختصر باللون السماوي، ثم دليل العمل مع اختصار الدليل الرئيسي إلى ~، ثم اسم الفرع باللون الأصفر عندما يكون الدليل مستودع git، ثم اسم النموذج بلون خافت. ويكون قريباً من web-01 ~/api main Opus، مع تلوين هذه الأجزاء الأربعة.

يعيد الصف تشغيل البرنامج النصي عند بدء الجلسة، بما في ذلك استئنافها، وعند وصول رسالة جديدة من المساعد، وبعد انتهاء /compact، وعند تغيّر وضع الأذونات، وعند تبديل وضع vim، وعند كل نبضة refreshInterval إذا ضبطت واحدة. تُؤجَّل التحديثات لمدة 300 ms، لذلك يؤدي تتابع التغييرات السريع إلى تشغيل البرنامج النصي مرة واحدة. يختفي الشريط أثناء الإكمال التلقائي، وقائمة المساعدة، ومطالبات الأذونات، ثم يظهر مجدداً.

لماذا يجب أن يظهر اسم المضيف أولاً

عندما تُبقي agents قيد التشغيل على أكثر من خادم، تكون الطرفية هي الشيء الوحيد الذي يخبرك بمكانك، لكن الطرفيات قد تكون مضللة. افتح اتصال ssh ثانياً من داخل جزء tmux، وغالباً ما يحتفظ عنوان النافذة بالاسم القديم، لأن العنوان تحدده shell لم تعرف أنها انتقلت. اترك Claude Code قيد التشغيل في جلسة tmux منفصلة على VPS، ثم أعد الاتصال بها بعد يوم، ولن تجد على الشاشة ما يميز خادم البناء عن خادم الإنتاج.

يختلف statusline لأنه يُعرض بواسطة Claude Code نفسه لكل جلسة، اعتماداً على البيانات التي تحتفظ بها تلك الجلسة. ولا يمكن أن يرث قيمة من الجزء الخطأ أو يبقى قديماً بسبب prompt لم تُحدّثه shell. ما يعرضه هو الخادم الذي يكتب عليه agent الملفات.

امنح كل خادم لوناً خاصاً به حتى تتعرف عليه قبل قراءة الاسم. أضف السطرين التاليين فوق إسناد LINE=:

CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")

ثم استخدم ${HOST_COLOR} بدلاً من ${CYAN}. يعرض cksum قيمة checksum لاسم المضيف، لذلك يُطابق الاسم نفسه دائماً اللون نفسه ضمن النطاق 31 إلى 36، من الأحمر إلى السماوي. انسخ script نفسه إلى كل خادم، وسيضع كل خادم علامته بنفسه.

يستحق الدليل مكانه للسبب نفسه. يفصل بين /srv/api و/srv/api-staging ضغطة مفتاح واحدة في أمر ssh، لكن تأثيرهما يفصل بين حادثتين مختلفتين تماماً. أما model وbranch فهما العنصران الآخران اللذان يستحقان المساحة: يوضح لك model الجلسة التي استأنفتها، ويبين لك branch ما إذا كان agent على وشك تنفيذ commit على main.

تجعل الشاشة الصغيرة كل ذلك أكثر وضوحاً، إذ لا يوجد عنوان نافذة يمكنك الرجوع إليه. إذا كان هذا هو إعدادك، فراجع تشغيل Claude Code من هاتف.

اجعل البرنامج النصي سريعاً

يعمل برنامجك النصي مع كل رسالة يرسلها المساعد، ويلغي Claude Code التنفيذ الجاري عند وصول تحديث جديد. لذلك يعرض البرنامج النصي البطيء نصاً قديماً أو لا يعرض أي نص.

تستغرق كل استدعاءات jq بضع ميلي ثوانٍ. أما git فهو الجزء الذي يبطئ التنفيذ: يستغرق git status في مستودع كبير مع ذاكرة تخزين مؤقت باردة مئات الميلي ثواني. يتجنب البرنامج النصي أعلاه git status عمداً، ويستدعي git branch --show-current الذي يقرأ .git/HEAD ويعيد النتيجة فوراً.

إذا أضفت عملية أثقل، فخزّن نتيجتها في ملف وحدّثها كل بضع ثوانٍ. اربط الملف بالجلسة:

CACHE="/tmp/statusline-$(field '.session_id')"

استخدم session_id، وليس $$. يمثّل $$ معرّف عملية البرنامج النصي، وهو يختلف في كل استدعاء، لذلك لا تصل ذاكرة التخزين المؤقت المرتبطة به إلى نتيجة محفوظة، وتتحمل التكلفة الكاملة في كل مرة. أما session_id فثابت طوال الجلسة ويختلف بين الجلسات، لذلك لا يمكن لجلسَتَي Claude Code في مستودعين مختلفين قراءة اسم الفرع المخزن مؤقتاً لدى إحداهما. تبقى الجلسات معزولة بهذه الطريقة عن قصد، لذلك يتطلب تسليم العمل من جلسة إلى أخرى خطوة مقصودة. وهذا هو الغرض من إرسال رسالة من جلسة Claude Code إلى جلسة أخرى.

هناك حد آخر يستحق المعرفة: لا يعمل tput cols داخل برنامج نصي لشريط الحالة. يلتقط Claude Code المخرجات بدلاً من ربط برنامجك النصي بالطرفية، لذلك لا توجد قيمة يمكن لميزة اكتشاف العرض قياسها. يضبط Claude Code متغيرَي البيئة COLUMNS وLINES قبل تشغيل الأمر، في الإصدار v2.1.153 والإصدارات الأحدث، لذلك اقرأ $COLUMNS عندما تحتاج إلى تحديد مقدار النص الذي ستطبعه.

لماذا يبقى سطر الحالة فارغاً

لا يظهر أي شيء على الإطلاق. تحقّق من بت التنفيذ باستخدام ls -l ~/.claude/statusline.sh، ثم شغّل البرنامج النصي يدوياً باستخدام الإدخال التجريبي أعلاه. إذا طبع سطراً في shell لكنه لم يطبعه في Claude Code، فابدأ باستخدام claude --debug، الذي يسجّل رمز الخروج وstderr لأول تشغيل لسطر الحالة في الجلسة.

يقول سجل التصحيح Status line command skipped: workspace trust not accepted. ينفّذ سطر الحالة أمراً في shell، لذلك يخضع لبوابة الثقة في مساحة العمل نفسها التي تخضع لها hooks. إلى أن تقبل مربع حوار الثقة لهذا الدليل، لن يُشغَّل الأمر. يحدث ذلك كثيراً على VPS، حيث تكون كل نسخة جديدة دليلاً لم يسبق أن رآه Claude Code. أعد تشغيل Claude Code في ذلك الدليل واقبل مربع الحوار.

كل شيء فارغ وdisableAllHooks مضبوط. يعطّل "disableAllHooks": true في settings.json سطر الحالة أيضاً، لأنه بوابة تنفيذ shell نفسها. أزله أو اضبطه على false.

يطبع الصف null. وصل محدد jq إلى مفتاح مفقود أو قيمته null، ويطبع jq -r القيمة null على شكل الأحرف الأربعة null. أضف // empty للنص و// 0 للأرقام.

يصبح الصف فارغاً مباشرة بعد تعديل البرنامج النصي. يؤدي أمر ينتهي برمز غير صفري، أو لا يطبع شيئاً، إلى إفراغ الصف. والسبب المعتاد هو سطر نهائي مثل [ -n "$BRANCH" ] && LINE="..."، الذي يخرج بالرمز 1 عندما يكون الفرع فارغاً، فيأخذ البرنامج النصي بأكمله رمز الخروج نفسه. اترك printf في النهاية، أو أضف exit 0.

تظهر رموز الهروب كنص حرفي مثل \e]8;; في الشريط. استخدم printf '%b' بدلاً من echo -e. تحتاج روابط OSC 8 القابلة للنقر أيضاً إلى طرفية تدعمها، وقد يزيل tmux أو SSH هذه المتتاليات، لذلك يكون استخدام الألوان العادية خياراً أكثر أماناً على خادم بعيد.

يُقتطع الجانب الأيمن من الصف. تشترك إشعارات النظام وعداد الرموز في الوضع المطوّل في هذا الصف من الجهة اليمنى، وتفقد الطرفية الضيقة الجزء المتداخل. اجعل الناتج قصيراً. للحصول على حساب فعلي للاستخدام بدلاً من رقم على شريط، راجع كيفية احتساب Claude Code للرموز المميزة.

FAQ

أين يوجد إعداد سطر الحالة في Claude Code؟

يوجد في settings.json، ضمن كتلة statusLine مع ضبط type على "command" وضبط command على مسار برنامج نصي أو أمر shell. توجد إعدادات المستخدم في ~/.claude/settings.json، وتنطبق على كل مشروع على ذلك الجهاز. توجد إعدادات المشروع في .claude/settings.json داخل المستودع، وتكون لها الأولوية في ذلك الدليل. تُعاد قراءة الإعدادات تلقائياً، لكن لا يظهر التغيير إلا عند مشغّل التحديث التالي، مثل رسالتك التالية.

لماذا يظهر سطر حالة Claude Code فارغاً؟

تغطي أربعة أسباب معظم الحالات. لا يحتوي البرنامج النصي على بت التنفيذ، لذلك يعرض shell الرمز Permission denied ولا يصل أي شيء إلى stdout. لم تُقبل نافذة حوار الثقة بمساحة العمل، ويسجّل claude --debug الرمز Status line command skipped: workspace trust not accepted. أو تكون قيمة disableAllHooks هي true، ما يعطّل سطر الحالة عبر البوابة نفسها. أو ينتهي البرنامج النصي برمز خروج غير صفري، فيصبح الصف فارغاً. اختبره يدوياً أولاً: يجب أن يطبع echo '{}' | ~/.claude/statusline.sh شيئاً.

هل يتضمن JSON الخاص بسطر الحالة فرع git؟

لا. يتضمن JSON حالة الجلسة، مثل النموذج، وأدلة مساحة العمل، وأرقام نافذة السياق، والتكلفة. ولا يقدّم أي شيء فيه معلومات عن git. يأتي الفرع الظاهر في الشريط من برنامجك النصي الذي يستدعي git branch --show-current. مرّر الدليل من JSON باستخدام git -C "$DIR"، حتى يطابق الفرع دائماً الدليل الذي يعرضه الشريط.

هل يستهلك سطر الحالة رموزاً أو يبطئ الجلسة؟

لا يستهلك أي رموز، لأن البرنامج النصي يعمل محلياً ولا تُرسل مخرجاته إلى النموذج. أما السرعة فهي مسؤوليتك. يُشغَّل الأمر مع كل رسالة من المساعد، مع تأخير 300 ms، ويلغي Claude Code عملية قيد التنفيذ عند وصول تحديث جديد. لذلك يعرض البرنامج النصي الذي يستغرق ثانية كاملة نصاً قديماً. تجنّب git status في المستودعات الكبيرة، وخزّن مؤقتاً أي عملية بطيئة في ملف يعتمد مفتاحه على session_id.

كيف أعرض سطر حالة مختلفاً على كل خادم؟

احتفظ ببرنامج نصي واحد واجعله يقرأ معلومات الجهاز. يطبع البرنامج النصي أعلاه $HOSTNAME مع استخدام hostname -s كقيمة احتياطية، لذلك يؤدي نسخ الملف نفسه إلى كل خادم إلى تسمية كل خادم بشكل صحيح، كما تمنح حيلة تلوين checksum كل اسم مضيف لوناً خاصاً به. إذا احتاج أحد الخوادم إلى تخطيط مختلف، فأضف كتلة statusLine إلى إعدادات المشروع في المستودع الذي تعمل فيه على ذلك الخادم، لأن إعدادات المشروع تتغلب على إعدادات المستخدم في ذلك الدليل.