الهندسة العكسية لميزة Agent Teams في Claude Code: البنية والبروتوكول

ترجمة آلية المقال الأصلي.

Banner for الهندسة العكسية لميزة Agent Teams في Claude Code: البنية والبروتوكول

المحتوى

مقدمة

يتضمّن Claude Code (v2.1.47) ميزة تجريبية تُسمّى Agent Teams: تنسّق عدة جلسات من Claude Code العمل المشترك ضمن بنية اتصال تضم قائدًا وأعضاء فريق. أعمل على تطوير Hive، وهو منسّق برمجة متعدد الوكلاء له أهداف مشابهة لكن ببنية مختلفة تمامًا، لذا أردت أن أفهم كيف يعمل نهج Anthropic من الداخل.

أوثّق في هذا المقال ما توصلت إليه من خلال:

  1. قراءة الوثائق الرسمية
  2. فحص الآثار الفعلية التي تركتها جلسات فرق سابقة على القرص
  3. ترك Claude يحلّل الملف الثنائي لـ Claude Code (v2.1.47) لاستخراج تفاصيل التنفيذ (هاها!)

جدول المحتويات

1. نظرة عامة على البنية

يتكوّن فريق الوكلاء من أربعة مكوّنات:

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

تعتمد طبقة التنسيق بأكملها على الملفات. فنظام الملفات في ~/.claude/ هو الركيزة الوحيدة للتنسيق:

~/.claude/
├── teams/{team-name}/
│   ├── config.json                  # team membership registry
│   └── inboxes/{agent-name}.json    # per-agent mailbox
└── tasks/{team-name}/
    ├── .lock                        # flock() for concurrent task claiming
    ├── .highwatermark               # auto-increment counter
    ├── 1.json                       # individual task files
    ├── 2.json
    └── ...

هذا تصميم لامركزي في جوهره. فالقائد ليس سوى جلسة Claude أخرى مزوّدة بأدوات إضافية (TeamCreate، TeamDelete، SendMessage). لا توجد عملية تعمل في الخلفية. ينشأ التنسيق من الوصول المشترك إلى الملفات.

في جلسة نشطة، إذا طلبت من Claude إنشاء فريق لتنفيذ مهمة ما ثم شغّلت ما يلي في نافذة أخرى، يمكنك مراقبة تحديث نظام الملفات لحظة بلحظة.

watch -n 0.5 'tree ~/.claude/teams/ 2>/dev/null; echo "---"; tree ~/.claude/tasks/ 2>/dev/null'

على سبيل المثال، باستخدام الموجّه التالي:

can you spawn an agent team to examine this codebase?
  - have one look for bugs
  - have one look for complexity
  - have one look for good things to call out and play devil's advocate against the other two agents

رصدت ما يلي:

teams
└── code-review
    ├── config.json
    └── inboxes
        ├── bug-hunter.json
        ├── complexity-analyst.json
        ├── devils-advocate.json
        └── team-lead.json

إعدادات الفريق

يحتوي ملف إعدادات الفريق في ~/.claude/teams/{team-name}/config.json على مصفوفة members يقرؤها أعضاء الفريق للتعرّف بعضهم إلى بعض:

{
  "members": [
    { "name": "team-lead", "agentId": "abc-123", "agentType": "leader" },
    {
      "name": "researcher",
      "agentId": "def-456",
      "agentType": "general-purpose"
    }
  ]
}

الأسماء هي الآلية الأساسية لتحديد وجهات الرسائل (توجد معرّفات UUID، لكنها لا تُستخدم للتوجيه). تستخدم جميع الرسائل وعمليات إسناد المهام الحقل name.

2. قائمة المهام المشتركة

صيغة الملفات

تُخزَّن كل مهمة في ملف JSON منفرد داخل ~/.claude/tasks/{team-name}/. إليك مثالًا فعليًا من جلسة سابقة:

{
  "id": "1",
  "subject": "Hunt for bugs across the codebase",
  "description": "...",
  "activeForm": "Hunting for bugs",
  "owner": "bug-hunter",
  "status": "completed",
  "blocks": [],
  "blockedBy": []
}

مخطط بيانات المهمة:

الحقل النوع الوصف
id string معرّف رقمي، تُزاد قيمته تلقائيًا عبر .highwatermark
subject string عنوان بصيغة الأمر (مثل "شغّل الاختبارات")
description string المتطلبات التفصيلية ومعايير القبول
activeForm string صيغة تصف إجراءً جاريًا للعرض مع مؤشر الانتظار ("جارٍ تشغيل الاختبارات")
status string pending → in_progress → completed (أو deleted)
blocks string[] معرّفات المهام التي تمنع هذه المهمة بدءها
blockedBy string[] معرّفات المهام التي يجب إكمالها قبل أن تبدأ هذه المهمة

التحكّم في التزامن

يوفّر ملفان خاصان التنسيق:

  • .lock: ملف حجمه 0 بايت يُستخدم لتحقيق الاستبعاد المتبادل على مستوى نظام الملفات (flock()). موجود في جميع مجلدات المهام الـ42 التي رصدتها على جهازي.
  • .highwatermark: يحتوي على عدد صحيح واحد (مثل "3"، "13"). وهو معرّف المهمة التالي المتاح للزيادة التلقائية.

تولّي المهام

تستخدم عملية تولّي المهام قفل الملفات لمنع حالات التسابق. يفضّل أعضاء الفريق البدء بالمهام ذات المعرّفات الأقل. ولا يمكن تولّي مهمة تحتوي على مصفوفة blockedBy غير فارغة حتى تصل جميع المهام التي تمنع بدءها إلى حالة نهائية.

ملاحظة: معظم مجلدات المهام فارغة

من أصل 42 مجلدًا للمهام على جهازي، لم يحتوِ على ملفات JSON فعلية للمهام سوى 5 مجلدات. أما المجلدات الـ37 المتبقية، فلم تحتوِ إلا على .lock و.highwatermark. وهذا يعني على الأرجح أن المهام تُزال بعد إكمالها، أو أن هذه كانت جلسات استخدم فيها Claude قائمة المهام الداخلية (المتاحة منذ إطلاق ميزة قائمة المهام) دون تقسيم العمل إلى ملفات مهام فرعية.

3. التواصل بين الوكلاء

نمط صندوق البريد

لكل وكيل ملف يحتوي على مصفوفة JSON في ~/.claude/teams/{team-name}/inboxes/{agent-name}.json. إليك صندوق وارد فعليًا من جلسة سابقة أسند فيها قائد الفريق عملًا إلى controlplane-agent:

[
  {
    "from": "team-lead",
    "text": "{\"type\":\"task_assignment\",\"taskId\":\"1\",\"subject\":\"Phase 2: Control-plane - remove participants/presence\",\"description\":\"Remove multiplayer code from the control-plane package...\",\"assignedBy\":\"team-lead\",\"timestamp\":\"2026-02-18T02:37:16.890Z\"}",
    "timestamp": "2026-02-18T02:37:16.890Z",
    "read": false
  }
]

لاحظ ترميز JSON داخل JSON: الحقل text عبارة عن سلسلة JSON نصية تحتوي على كائن رسالة مُسلسَل. ويتضمّن الغلاف الخارجي الحقول from وtext وtimestamp وread.

أنواع الرسائل

يدعم الحقل type داخل حمولة text الأنواع التالية:

النوع الاتجاه الغرض
task_assignment القائد → عضو الفريق إسناد مهمة بتفاصيلها الكاملة
message أي وكيل → أي وكيل رسالة مباشرة إلى مستلِم واحد
broadcast القائد → الجميع الرسالة نفسها لكل عضو في الفريق
shutdown_request القائد → عضو الفريق طلب إيقاف منظّم
shutdown_response عضو الفريق → القائد الموافقة على الإيقاف أو رفضه
plan_approval_request عضو الفريق → القائد تقديم خطة للمراجعة
plan_approval_response القائد → عضو الفريق الموافقة أو الرفض مع تقديم ملاحظات
idle_notification عضو الفريق → القائد تُرسَل تلقائيًا عند انتهاء دور عضو الفريق

آلية التوصيل

مسار الكتابة: يُلحق المُرسِل إدخالًا جديدًا بمصفوفة JSON في ملف صندوق وارد المستلِم.

مسار القراءة: يفحص المستلِم ملف صندوق الوارد الخاص به دوريًا. وتُدرَج الرسائل الجديدة كأدوار محادثة اصطناعية (فتبدو كما لو أن مستخدمًا أرسلها).

البث الجماعي: يكتب الرسالة نفسها حرفيًا في ملف صندوق الوارد لكل عضو في الفريق. تزداد تكلفة التوكنات خطيًا مع حجم الفريق.

التواصل ليس سوى إلحاق بالملف + قراءة منه. ويعتمد زمن التأخير بين الإرسال والاستلام على الفاصل الزمني بين عمليات الفحص لدى المستلِم.

الاطّلاع على الرسائل المباشرة بين الأعضاء

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

4. إنشاء الوكلاء ودورة حياتهم

كيفية إنشاء أعضاء الفريق

كل عضو في الفريق هو عملية مستقلة لواجهة سطر الأوامر claude. ينشئها القائد عبر الأداة Task مع المعاملين team_name وname. وتُضبط متغيرات البيئة التالية للعملية المُنشأة:

  • CLAUDE_CODE_TEAM_NAME: يُضبط تلقائيًا لأعضاء الفريق عند إنشائهم
  • CLAUDE_CODE_PLAN_MODE_REQUIRED: يُضبط على true إذا كانت الموافقة على الخطة مطلوبة

تهيئة السياق

يحمّل أعضاء الفريق سياق المشروع نفسه الذي تحمّله أي جلسة جديدة:

  • ملفات CLAUDE.md من مجلد العمل
  • خوادم MCP
  • المهارات
  • موجّه الإنشاء الذي يقدّمه القائد

لا يُنقل سجل محادثة القائد. يبدأ كل عضو في الفريق من الصفر، ولا يملك من السياق إلا موجّه الإنشاء.

التنفيذ الداخلي

تبيّن من تحليل الملف الثنائي لـ Claude Code v2.1.47 أن سياق عضو الفريق يُدار عبر AsyncLocalStorage باستخدام الحقول التالية:

  • agentId، agentName، teamName
  • parentSessionId، color
  • planModeRequired

الدوال الداخلية الرئيسية:

  • isTeammate() / isTeamLead(): تحديد الدور
  • waitForTeammatesToBecomeIdle(): آلية مزامنة أساسية للقائد
  • getTeammateContext() / setDynamicTeamContext(): إدارة السياق أثناء التشغيل

اكتشاف الخمول

بعد كل دور للنموذج اللغوي الكبير، ينتقل عضو الفريق تلقائيًا إلى حالة الخمول ويرسل idle_notification إلى القائد. هذه هي حالة الانتظار الطبيعية، وليست حالة خطأ أو تقادم. وإرسال رسالة إلى عضو خامل يعيد تنشيطه (تلتقط دورة الفحص التالية رسالة صندوق الوارد).

بروتوكول الإيقاف

  1. يرسل القائد shutdown_request إلى عضو في الفريق
  2. يمكن للعضو الموافقة (فيخرج بشكل منظّم) أو الرفض (فيواصل العمل مع تقديم تفسير)
  3. يؤدي تنظيف الفريق عبر TeamDelete إلى إزالة ~/.claude/teams/{team-name}/ و~/.claude/tasks/{team-name}/
  4. يفشل التنظيف إذا كان أي عضو في الفريق لا يزال نشطًا؛ إذ يجب إيقافهم أولًا

وراثة الأذونات

يرث أعضاء الفريق وضع أذونات القائد لحظة إنشائهم. إذا كان القائد يعمل باستخدام --dangerously-skip-permissions، فإن جميع أعضاء الفريق يعملون به أيضًا. يمكن تغيير أوضاع الأعضاء كلٍّ على حدة بعد الإنشاء، لكن لا يمكن ضبط وضع مستقل لكل عضو عند إنشائه.

5. بوابات الجودة والخطافات

تتكامل ميزة Agent Teams مع نظام الخطافات في Claude Code لفرض متطلبات الجودة:

خطاف TeammateIdle

يُفعَّل عندما يكون عضو الفريق على وشك الانتقال إلى الخمول. عند إرجاع رمز الخروج 2، يُرسَل محتوى stderr كملاحظات ويُمنَع الانتقال إلى الخمول، مما يُبقي عضو الفريق يعمل.

{
  "hook_event_name": "TeammateIdle",
  "teammate_name": "researcher",
  "team_name": "my-project"
}

خطاف TaskCompleted

يُفعَّل عند وضع علامة الاكتمال على مهمة. يمنع رمز الخروج 2 إكمالها ويعيد محتوى stderr كملاحظات.

{
  "hook_event_name": "TaskCompleted",
  "task_id": "task-001",
  "task_subject": "Implement user authentication",
  "task_description": "Add login and signup endpoints",
  "teammate_name": "implementer",
  "team_name": "my-project"
}

يُفعَّل هذا الخطاف في حالتين: (1) عندما يضع أي وكيل صراحةً علامة الاكتمال على مهمة عبر TaskUpdate، أو (2) عندما ينهي أحد أعضاء فريق الوكلاء دوره ولديه مهام قيد التنفيذ.

أنواع معالجات الخطافات

النوع الوصف
command برنامج نصي لـ Shell. يُمرَّر JSON عبر stdin، وتحدّد رموز الخروج القرارات.
prompt تقييم يجريه نموذج لغوي كبير في دور واحد. يُرجع {ok, reason}.
agent وكيل فرعي يعمل لعدة أدوار ومزوّد بأدوات قراءة. حتى 50 دورًا.

6. اقتصاديات التوكنات

تستهلك فرق الوكلاء نحو 7 أضعاف عدد التوكنات الذي تستهلكه الجلسات المعتادة عندما يعمل أعضاء الفريق في وضع التخطيط. يحتفظ كل عضو في الفريق بنافذة سياق كاملة خاصة به بوصفه نسخة مستقلة من Claude.

القيم المرجعية الأساسية

  • متوسط استخدام Claude Code: نحو 6 دولارات/مطوّر/يوم
  • فرق الوكلاء: تكلفة تتناسب تقريبًا مع حجم الفريق، وتُضاف إلى التكلفة الأساسية

7. ملخص البنية

البُعد فرق الوكلاء في Claude Code
ركيزة التنسيق ملفات مسطّحة (~/.claude/tasks/، ~/.claude/teams/)
صيغة المهام ملف JSON واحد لكل مهمة + .lock لتولّي المهام
تبادل الرسائل ملفات صندوق وارد بصيغة JSON (إلحاق + فحص دوري)
دورة حياة الوكلاء عمليات لواجهة سطر الأوامر تدير نفسها
عزل العمل مجلد عمل مشترك
استراتيجية الدمج لا توجد (يعدّل الوكلاء الملفات مباشرةً)
إعادة المحاولة/التصعيد يدويان (يقرّر القائد أو يتدخل المستخدم)
بنية الاتصال قائد + أعضاء على مستوى واحد، ومراسلة مباشرة بين الأعضاء
الجدولة تولٍّ ذاتي (يتولّى أعضاء الفريق المهمة التالية)
ديمومة الحالة ملفات فقط؛ لا يوجد استئناف لأعضاء الفريق داخل العملية
بوابات الجودة خطافات Shell (TeammateIdle، TaskCompleted)
تتبّع التوكنات لكل جلسة فقط، دون تجميع عبر الوكلاء
اكتشاف التوقف عن التقدّم يدوي (يلاحظ المستخدم أن عضو الفريق توقف)
التحكّم في التزامن ضمني (حجم الفريق = عدد أعضائه)
نموذج الاعتماديات blocks/blockedBy في ملفات المهام

المصادر

الوثائق الرسمية

الآثار المتروكة على القرص (Claude Code v2.1.47)

رُصدت في /Users/tau/.claude/:

  • مجلدات فرق تحتوي على ملفات config.json وinboxes/{agent-name}.json
  • مجلدات مهام تحتوي على .lock و.highwatermark وملفات JSON منفردة للمهام
  • نموذج لرسالة إسناد مهمة من team-lead إلى cp-agent، تحمل الطابع الزمني 2026-02-18T02:37:16.890Z

تحليل الملف الثنائي

الملف الثنائي لـ Claude Code v2.1.47. الدوال الداخلية التي حُدّدت بتحليل السلاسل النصية: getTeamName، getAgentName، getAgentId، isTeammate، isTeamLead، waitForTeammatesToBecomeIdle، getTeammateContext، setDynamicTeamContext، createTeammateContext. حقول سياق AsyncLocalStorage: agentId، agentName، teamName، parentSessionId، color، planModeRequired.

قاعدة شيفرة Hive