tooling

تعديلات Claude Code: ١٠ حالات استخدام مُجربة (٢٠٢٦)

٩ أكتوبر ٢٠٢٦

Claude Code Mods: 10 Tested Use Cases (2026)

تعد إضافات Claude Code (المعروفة بـ mods) عبارة عن ملحقات تعمل وظائف الـ JavaScript أو TypeScript الخاصة بها داخل Claude Code عند وقوع حدث معين: استدعاء أداة، أو مطالبة (prompt)، أو دورة (turn)، أو إعادة رسم. أدناه يوجد 10 إضافات تعمل لمهام شائعة، بدءاً من حماية الأوامر الخطيرة وصولاً إلى رسم الأجزاء (panes)، وكل واحدة منها تجتاز claude plugin test.

ملخص

أضافت Anthropic الإضافات (mods) إلى Claude Code في 1 أكتوبر 2026، في الإصدار 2.1.287.12 تقوم الإضافة بربط حدث معين ويمكنها مراقبته، أو إعادة كتابته، أو الرد عليه بدلاً من Claude Code، كما يمكنها رسم أجزاء (panes)، وأشرطة (bands)، وخطوط حالة خاصة بها.3

لقد كتبنا 10 إضافات للمهام اليومية وتحققنا منها على Claude Code 2.1.295. جميع الإضافات العشر تجتاز claude plugin validate، وجميع اختبارات الوحدة الـ 25 تجتاز بنجاح، كما أن ستة منها عملت كما هو متوقع في عمليات تشغيل claude -p حية. الكود أدناه منسوخ من الملفات التي تم اختبارها.

تعمل الإضافات بصلاحياتك وليست معزولة (sandboxed)، لذا اقرأ الإضافة قبل تثبيتها.3

ما ستتعلمه

  • ما هي إضافة Claude Code، ومتى تختارها بدلاً من خطافات الإعدادات (settings hooks)، أو المهارات (skills)، أو خادم MCP
  • الملفات الثلاثة التي تحتاجها كل إضافة، وكيفية تحميلها والتحقق منها واختبارها
  • 10 حالات استخدام مختبرة مع الكود الكامل: حواجز الأمان، سياق المطالبة، الأوامر، الأجزاء، أداة مخصصة ومراقب خلفي
  • ما الذي تغير في الأسبوع الأول بعد الإطلاق، والقيود التي قد تسبب ارتباكاً للمستخدمين
  • كيف تتحكم الفرق والمؤسسات في الإضافات التي يتم تشغيلها

ما هي إضافة Claude Code؟

إضافة Claude Code هي ملحق يقوم الكود الخاص به بتسجيل معالجات للأحداث، تسمى خطافات (hooks).

توضح وثائق Anthropic الأمر كالتالي: "الإضافة هي ملحق يغير مظهر وسلوك Claude Code. وهي تتكون من معالجات أحداث JavaScript أو TypeScript."3 ويصفها الإعلان بأنها "وظائف TypeScript صغيرة" يمكنها إعادة كتابة مطالبة، أو إضافة واجهة مستخدم جديدة، أو استبدال ميزة مدمجة، أو إضافة وظائف جديدة.1

يحصل كل خطاف على نفس الوسائط الثلاثة:4

  • $، وهو API الخاص بالإضافات: كل طريقة يمكن للإضافة استدعاؤها، مجمعة في مساحات أسماء مثل $.ui و $.fs و $.process
  • e، وهو الحدث: بيانات بسيطة ومجمدة مثل اسم استدعاء الأداة ووسائطها
  • next، وهو المعالج التالي: يقوم بتمرير الحدث إلى الإضافات الأخرى ثم إلى سلوك Claude Code نفسه

ما يفعله الخطاف بـ next هو ما يحدد نوع الخطاف. إذا قمت بإرجاع next(e) فهو يقوم فقط بـ المراقبة. وإذا مررت لـ next نسخة معدلة فهو يقوم بـ إعادة كتابة الحدث. أما إذا أرجعت نتيجة دون استدعاء next فهو يقوم بـ الرد على الحدث بنفسه، وبالتالي لا يتم تشغيل سلوك Claude Code الأصلي أبداً.5

الإضافات مقابل خطافات الإعدادات، المهارات وخوادم MCP

كان Claude Code يحتوي بالفعل على خطافات إعدادات، ومهارات، وخوادم MCP، وتقارن الوثائق بين الأربعة. باختصار: الإضافة هي الوحيدة التي تعمل داخل عملية (process) Claude Code والوحيدة التي يمكنها الرسم في واجهة المستخدم.3

ModSettings hookSkillMCP server
ما هووظائف في إضافة (plugin) يستدعيها Claude Code في عمليته الخاصةأمر shell، أو طلب HTTP، أو prompt يقوم Claude Code بتشغيله عند حدث في دورة الحياة (lifecycle event)ملف تعليمات SKILL.md يقرأه Claudeعملية أو خدمة خارجية تمنح Claude أدوات
ما الذي يمكنه تغييرهاستدعاءات الأدوات، الـ prompts، الأوامر، الأدوار (turns)، وما ترسمه الواجهةما إذا كان استدعاء الأداة أو الـ prompt سيستمر، وسائط ونتيجة استدعاء الأداة، والسياق المضاف لـ Claudeما يعرفه Claude وما يفعلهالأدوات التي يمتلكها Claude
هل يمكنه الرسم في الواجهةنعملالالا
ما الذي تكتبهJavaScript أو TypeScriptسكربت بالإضافة إلى إدخال في settings.jsonMarkdownسيرفر بأي لغة برمجة
اختره عندماتريد لوحة (pane)، أو شريطاً فوق الـ prompt، أو أمراً مخصصاً، أو إعادة كتابة حدث ماتريد حظر أو السماح أو تسجيل حدث باستخدام سكربت لديك بالفعلتستمر في لصق نفس التعليمات في الدردشةيحتاج Claude للوصول إلى نظام خارجي

مقتبس من وثائق Claude Code، "Mods overview".3 يمكن للإضافة أن تحتوي على العناصر الأربعة معاً، لذا يمكن شحن mod بجانب skill و MCP server.

كيف تقوم ببناء واختبار Claude Code mod؟

تحتاج إلى Claude Code 2.1.287 أو إصدار أحدث في الـ terminal. علامة تبويب Code في تطبيق Desktop تشغل الـ mods من إصدار 2.1.286.3 لا تحتاج إلى Node.js أو خطوة بناء (build step)، لأن Claude Code يحمل ملفات .js و .ts مباشرة.4

يتكون الـ mod من ثلاثة ملفات:46

my-mod/
├── .claude-plugin/
│   └── plugin.json      # the plugin manifest: name, version, description
└── hooks/
    ├── hooks.json       # {"modules": ["./register.js"]} points at your code
    └── register.js      # your hooks module, which exports register(on)

كل mod في هذا المنشور يستخدم نفس ملفي JSON، مع تغيير الاسم والوصف فقط. إليك الملفات الخاصة بالأول:

{
  "name": "confirm-risky",
  "version": "0.1.0",
  "description": "Asks before Claude runs a destructive shell command",
  "author": { "name": "NerdLevelTech" }
}
{
  "modules": ["./register.js"]
}

ثلاثة أوامر تغطي الدورة الكاملة:476

# Load the mod for one session; Claude Code hot-reloads it when you save
claude --plugin-dir ./confirm-risky

# See what Claude Code reads from the mod: the events it hooks and the API calls it makes
claude plugin validate ./confirm-risky

# Run the mod's *.test.ts files with no session, sign-in or network
cd confirm-risky && claude plugin test

يمكنك أيضاً وصف الـ mod الذي تريده في جلسة Claude Code وتترك Claude يكتبه. يستخدم Claude مهارة (skill) مدمجة تسمى plugin-authoring لهذا الغرض، ولا يعمل الـ mod إلا بعد موافقتك عليه.4

كيف اختبرنا هذه الـ 10 mods

كتبنا كل mod يدوياً من الوثائق الرسمية وتصريحات الأنواع (type declarations) التي يشحنها Claude Code لإصداره، ثم أجرينا ثلاثة فحوصات في 9 أكتوبر 2026 باستخدام Claude Code 2.1.295:

  1. claude plugin validate على كل mod. اجتازت جميع الـ 10 الفحص.
  2. claude plugin test مع 2 إلى 4 اختبارات لكل mod، بإجمالي 25 اختباراً. اجتازت جميع الـ 25 الفحص.
  3. تشغيل مباشر لـ claude -p باستخدام نموذج Haiku في مستودع git مؤقت، لسبعة mods. ستة منها عملت كما هو متوقع. السابع، وهو turn receipt، اجتاز اختباراته، ولكن claude -p يطبع الإجابة فقط، لذا لا يظهر السطر الخاص به هناك وقد تحققنا منه عبر الاختبارات فقط.

تظهر الـ Mods التي تقوم بالرسم فقط في الطرفية (terminal) التفاعلية أو تطبيق سطح المكتب.3 لقد قمنا برسم الشريط واللوحة باستخدام $.ui.mount الخاصة بمجموعة أدوات الاختبار، والتي تقوم بتصيير موقع بدون جلسة، وتحققنا من سطر الحالة عن طريق عمل stub لـ $.ui.status.7

الاختبار هو ملف TypeScript يقوم بإثارة الأحداث وعمل stub لأي شيء قد يجيب عليه Claude Code. هذا هو الاختبار الخاص بـ push guard في حالة الاستخدام 2. يقوم بالرد على $.process.run باسم فرع وهمي، لذا لا يتم تشغيل أي git:7

import { expect, test } from 'claude-code/testing'

// Stubs what the permission rules decided and what git says the current branch is,
// and counts how often the mod ran git
function stubs(on, branch: string, rules = 'allow') {
  const runs = { git: 0 }
  on('tool.check', () => ({ decision: rules }))
  on('process.run', () => {
    runs.git += 1
    return { value: { exitCode: 0, stdout: branch + '\n', stderr: '' } }
  })
  return runs
}

test('git push while main is checked out is denied', async ($, on) => {
  stubs(on, 'main')
  const out = await $.tool.check({ tool: 'Bash', input: { command: 'git push' } })
  expect(out.decision).toBe('deny')
})

test('a push that targets main from another branch is denied', async ($, on) => {
  stubs(on, 'feature/login')
  for (const command of ['git push origin main', 'git push origin HEAD:main', 'git push origin +main', 'git push origin feature/login:refs/heads/main', 'git push --force origin main;', 'git push origin "main"']) {
    const out = await $.tool.check({ tool: 'Bash', input: { command } })
    expect(out.decision).toBe('deny')
  }
})

test('a feature branch push keeps the rules decision', async ($, on) => {
  stubs(on, 'feature/login')
  const out = await $.tool.check({ tool: 'Bash', input: { command: 'git push origin feature/login' } })
  expect(out.decision).toBe('allow')
})

test('other commands never run git', async ($, on) => {
  const runs = stubs(on, 'main', 'ask')
  const out = await $.tool.check({ tool: 'Bash', input: { command: 'npm test' } })
  expect(out.decision).toBe('ask')
  expect(runs.git).toBe(0)
})

مخرجات الطرفية من Claude Code 2.1.295 تظهر نجاح claude plugin validate لـ push-guard mod، ونجاح اختباراته الأربعة، وعدد مرات النجاح والفشل للتسعة mods الأخرى. تم إزالة التوقيتات واختصار المسارات.

جدول يوضح الـ 10 Claude Code mods التي تم بناؤها لهذا الدليل، مع الأحداث التي يستخدمها كل منها، وما يفعله الـ hook الخاص بها، وأين تظهر، وعدد اختباراتها، وما إذا كان قد تم التحقق منها أيضاً في تشغيل claude -p مباشر.

1. السؤال قبل أن يقوم Claude بتشغيل أمر shell تدميري

استخدم هذا إذا كنت تسمح لـ Claude بتشغيل أوامر shell ولكنك تريد مراجعة بشرية للأوامر التي لا يمكن التراجع عنها.

يمكن لـ hook من نوع tool.call إيقاف استدعاء الأداة بينما يطرح عليك سؤالاً. يقوم $.ui.ask بإظهار السؤال في الحوار الذي يستخدمه Claude للأسئلة وينتهي بالوصول إلى التسمية (label) التي تختارها. يتم رفض الطلب عندما تغلقه، وفي تشغيل claude -p حيث لا يمكن لأحد الإجابة.5 لذا يبدأ الـ hook من "الرفض" (Refuse) ولا يشغل الأمر إلا عند اختيار "تشغيله" (Run it) بشكل صريح.

// Commands worth a second look: recursive deletes (rm -r, -R, -rf, -f -r, rm dir -rf, --recursive),
// hard resets, and force pushes (--force, -f, or a +branch refspec)
const RISKY = [
  /\brm\b.*\s-[a-zA-Z]*[rR][a-zA-Z]*(?=\s|$)/,
  /\brm\b.*\s--recursive\b/,
  /\bgit\s+reset\s+--hard\b/,
  /\bgit\s+push\b.*(?:\s--force\b|\s-f\b|\s\+\S)/,
]

export function register(on) {
  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
    // Everything else runs as usual
    if (!RISKY.some((pattern) => pattern.test(e.command))) return next(e)
    // Start from the safe answer, so a question nobody answers refuses the command
    let answer = 'Refuse'
    try {
      // The tool call waits here until you pick an option; Refuse is listed first
      answer = await $.ui.ask('Run this command? ' + e.command, ['Refuse', 'Run it'])
    } catch {
      // Dismissed, or a claude -p run with nobody to ask
    }
    if (answer !== 'Run it') {
      return { deny: 'The user declined this command. Ask before trying another approach.' }
    }
    return next(e)
  }).catch(async ($, e, next) => {
    // If the guard itself fails before the command ran, refuse instead of failing open
    return next.called ? next(e) : { deny: 'The confirm-risky guard failed, so this command was not run.' }
  })
}

تعتبر .catch مهمة هنا. أي hook يتسبب في خطأ (throw) أو ينتهي وقته قبل استدعاء next يتم تخطيه، وسيعمل الأمر. يقوم معالج .catch بالرد بدلاً منه، لذا فإن هذا الحارس يفشل في حالة الإغلاق (fails closed).5

تغطي ثلاثة اختبارات ستة أوامر آمنة يجب ألا تثير سؤالاً (من بينها rm notes.txt و docker rm -f web و npm run build -- --force-color)، وثمانية أوامر خطيرة يجب رفضها (rm -rf و rm -Rf و rm -R و rm -f -r و rm build -rf و rm --recursive و git reset --hard و force push لـ +main)، وأمر git push -f معتمد.

في تجربة حية، طلبنا من Claude تشغيل rm build -rf مع تحميل الـ mod. رد Claude قائلاً "تم رفض الأمر، لذا لم يتم تشغيل أي شيء و build لم يمس". وكان مجلد build لا يزال موجوداً.

تنبيه واحد: الأنماط تعتمد على مطابقة النصوص. فهي تغفل الأوامر التدميرية التي لا تشبه هذه الأنماط، مثل find . -delete أو سكربت يقوم بحذف الملفات، لذا تعامل مع الـ mod كمطب للسرعة وليس كبيئة معزولة (sandbox). يمكنه أيضاً السؤال عن أوامر غير ضارة، مثل تشغيل grep -r بعد git rm. تم وضع "الرفض" (Refuse) أولاً عن قصد، حتى لا يؤدي الضغط غير المقصود على Enter إلى تشغيل الأمر.

2. منع الـ pushes إلى main، بغض النظر عما تقوله القواعد

هذا مخصص للفرق التي تريد من Claude أن يقوم بعمل push لفروع الميزات (feature branches) ولكن ليس لـ main أبداً.

يتم إطلاق tool.check بعد أن تقرر قواعد الأذونات و hooks الإعدادات ما إذا كان الاستدعاء يمكن أن يعمل، وينتهي next(e) بهذا القرار: allow (سماح)، أو ask (سؤال)، أو deny (رفض). يمكن للـ hook أن يعيد قراراً مختلفاً.5

وهذا يجعلها الحدث المناسب لفحص يعتمد على ما هو صحيح في الوقت الحالي، مثل الفرع الحالي. يرفض هذا التعديل (mod) أي عملية push تحدد main كهدف لها (origin main، أو HEAD:main، أو +main، أو refs/heads/main أو "main" بين علامتي تنصيص)، وأي عملية push بينما يكون main هو الفرع النشط (checked out).

export function register(on) {
  // tool.check fires after your permission rules and settings hooks have decided
  on('tool.check', { tool: 'Bash' }, async ($, e, next) => {
    // What the rules decided: allow, ask, or deny
    const decided = await next(e)
    const command = e.input.command
    if (!/\bgit\s+push\b/.test(command)) return decided
    // A push that names main as its target: "origin main", "HEAD:main", "+main", "refs/heads/main", "'main'"
    const namesMain = /\bgit\s+push\b.*(?:[\s:+'"]|refs\/heads\/)main(?=$|[\s;&|'"])/.test(command)
    // Or any push while main is checked out
    const branch = await $.process.run(['git', 'branch', '--show-current'])
    const onMain = branch.exitCode === 0 && branch.stdout.trim() === 'main'
    if (!namesMain && !onMain) return decided
    return { decision: 'deny', reason: 'Pushing to main is blocked here. Push a feature branch and open a pull request instead.' }
  }).catch(async ($, e, next) => {
    // If the check fails, for example git can't run, refuse the push rather than let it through
    return { decision: 'deny', reason: 'push-guard could not check this push (' + next.error.kind + '), so it was refused.' }
  })
}

هناك أربعة اختبارات تحاكي اسم الفرع وقرار القواعد، واختبار واحد يحسب عدد مرات تشغيل git لإثبات أن الأوامر الأخرى لا تقوم بتشغيله أبداً.

في التجربة الحية، ومع السماح بـ Bash(git push:*)، أدى تنفيذ git push origin main على فرع main إلى ظهور رسالة "Permission to use Bash denied by plugin push-guard: Pushing to main is blocked here. Push a feature branch and open a pull request instead."

ومن فرع يسمى feature/demo، حصلت أوامر git push origin HEAD:main و git push origin +main على نفس الرفض، ولم يحتوي المستودع البعيد (remote) إلا على فرع feature/demo.

أما عملية push لفرع feature/demo نفسه فقد كانت مسموحة وأبلغت بأن "Everything up-to-date".

ترفض .catch عملية الـ push إذا فشل الفحص نفسه، على سبيل المثال عندما لا يمكن تشغيل git. ومع ذلك، تقول الوثائق بوضوح أن الـ hook الذي يطابق نص الأمر هو مجرد تذكير لـ Claude. فأي صيغة لا يتوقعها النمط، مثل git -C . push، ستمر. كما يمكن رفض أمر غير ضار أيضاً، مثل git push origin feature/login && git log main. لمنع عمليات الـ push إلى main للجميع، قم بحماية الفرع على مستضيف Git الخاص بك.5

3. إخفاء الأسرار في مخرجات الأوامر قبل أن يقرأها Claude

استخدم هذا الحل عندما يمكن أن تحتوي مخرجات الـ shell على بيانات اعتماد، مثل ملفات تكوين السحابة أو تفريغ لبيانات البيئة (environment dumps).

يسمح هذا الـ hook بتشغيل الأمر، ثم يعيد كتابة ما نتج عنه. تذكر الإعلانات أن تنقيح الأسرار من مخرجات الأدوات هو أحد الأشياء التي يمكن للتعديل (mod) القيام بها باستخدام دالة واحدة.1 إن إرجاع كائن result جديد، بدلاً من الكائن الذي قدمه لك next، هو ما يجعل Claude يقرأ نسختك أنت.

الأمر الفاشل يحتاج إلى مسار معالجة خاص به. تعود مخرجاته مع تعيين isError والنص الذي يقرأه Claude يكون في text، وليس في stdout.8 يقوم التعديل بإخفاء هذا النص وإرجاعه كـ deny، بحيث لا يقرأ Claude إلا النص المخفي.

// Common credentials: AWS key ids (AKIA, ASIA), AWS secret keys and session tokens,
// GitHub tokens, Slack tokens, and private key blocks
const SECRETS = [
  [/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g, '[REDACTED]'],
  [/\b(aws_secret_access_key|aws_session_token)(\s*[=:]\s*)\S+/gi, '$1$2[REDACTED]'],
  [/\bgh[pousr]_[A-Za-z0-9]{36,}\b/g, '[REDACTED]'],
  [/\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, '[REDACTED]'],
  [/\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g, '[REDACTED]'],
  [/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, '[REDACTED]'],
]

function redact(text) {
  return SECRETS.reduce((out, [pattern, replacement]) => out.replace(pattern, replacement), text)
}

export function register(on) {
  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
    // Let the command run, then look at what it printed
    const ran = await next(e)
    // A refused call has nothing to clean
    if (ran.deny !== undefined) return ran
    if (ran.isError) {
      // A failed command's output reaches Claude as error text
      const text = typeof ran.text === 'string' ? ran.text : typeof ran.result === 'string' ? ran.result : ''
      const masked = redact(text)
      if (masked === text) return ran
      $.ui.log('masked a credential in the error output of: ' + e.command.slice(0, 60))
      // An error result can't be rewritten in place, so withhold it and pass on the masked text
      return { deny: masked }
    }
    // Another mod may have answered with a plain string; leave that alone
    if (typeof ran.result !== 'object' || ran.result === null) return ran
    const stdout = redact(ran.result.stdout ?? '')
    const stderr = redact(ran.result.stderr ?? '')
    if (stdout === ran.result.stdout && stderr === ran.result.stderr) return ran
    $.ui.log('masked a credential in the output of: ' + e.command.slice(0, 60))
    // Return a new result, so Claude reads the masked text and not the original
    return { result: { ...ran.result, stdout, stderr } }
  }).catch(async () => {
    // If masking itself fails, withhold the output rather than pass it on unmasked
    return { deny: 'mask-secrets could not check this output, so it was withheld.' }
  })
}

تتحقق أربعة اختبارات من إخفاء معرف مفتاح AWS والمفتاح السري، ومن مرور المخرجات النظيفة والأخطاء النظيفة دون تغيير، ومن إخفاء المفتاح في الأمر الفاشل، ومن قيام .catch بحجب المخرجات إذا فشلت عملية الإخفاء.

في التجربة الحية، وضعنا ملف بيانات اعتماد AWS وهمي في creds.txt وطلبنا من Claude اقتباس cat creds.txt__PRESERSEVERE__ حرفياً. مع وجود التعديل، اقتبس Claude aws_access_key_id = [REDACTED] و aws_secret_access_key = [REDACTED]. وبدونه، اقتبست محاولة سابقة لنفس الأمر معرف المفتاح الوهمي كاملاً. كما أن الأمر الفاشل، cat creds.txt; exit 3، عاد مخفياً أيضاً.

هذا يغطي مخرجات Bash والأنماط المدرجة فقط. لا يزال بإمكان Claude فتح نفس الملف باستخدام أداة Read، لذا قم بدمج هذا الحل مع حماية لعمليات القراءة. يوضح منشورنا السابق أحد هذه الحلول: تعديل لـ Claude Code يمنع قراءة ملفات .env.

4. إضافة فرع git الحالي إلى المطالبات المتعلقة بطلبات السحب (pull requests)

هذا يوفر عليك كتابة حقائق المستودع في كل مطالبة.

ترى هوك prompt.submit كل أمر (prompt) قبل بدء الدور. تمرير حدث يحتوي على إدخال context إضافي إلى next يضيف نصاً يقرأه Claude بعد الأمر الخاص بك، بينما يظل السجل (transcript) يعرض ما كتبته فقط.5

export function register(on) {
  on('prompt.submit', async ($, e, next) => {
    // Leave prompts that don't mention a pull request alone
    if (!/\bPR\b|pull request/i.test(e.text)) return next(e)
    let git
    try {
      git = await $.process.run(['git', 'branch', '--show-current'])
    } catch {
      // git isn't installed, so send the prompt as it is
      return next(e)
    }
    // Outside a git repository there is no branch to add
    if (git.exitCode !== 0) return next(e)
    // Claude reads this line after your prompt; the transcript still shows what you typed
    return next({ ...e, context: [...(e.context ?? []), 'Current branch: ' + git.stdout.trim()] })
  })
}

يتحقق اختباران من أن الأمر الذي يشير إلى PR يحصل على Current branch: feature/auth، ويقومان بعد مرات تشغيل git لإثبات أن الأوامر الأخرى لا تشغله أبداً. في الواقع، ومع تعطيل Bash حتى لا يتمكن Claude من البحث عنها، حصل أمر يشير إلى PR على الإجابة feature/demo. أما السؤال الذي لا يشير إلى PR فقد حصل على "Unknown"، لأنه لم يتم إضافة أي فرع (branch).

يقرأ Claude السطر المضاف مع كل أمر مطابق، لذا اجعله قصيراً وأضفه فقط عندما يكون مفيداً، كما يفعل هذا التعديل (mod).

5. إضافة أمر "slash" فوري يتجاوز النموذج

بعض عمليات البحث لا تحتاج إلى تفكير Claude على الإطلاق.

الأمر المسجل بواسطة mod يقوم بتشغيل الدالة الخاصة بك على الفور، دون أي دور لـ Claude.3 قم بتسجيله في session.start، وأجب عليه في command.run، وأضف immediate: true ليعمل أيضاً بينما يكون Claude مشغولاً.9

export function register(on) {
  on('session.start', async ($, e, next) => {
    // immediate: true lets /todos run even while Claude is working
    await $.command.register({ name: 'todos', description: 'List TODO and FIXME lines in tracked files', immediate: true })
    return next(e)
  })

  on('command.run', { command: 'todos' }, async ($) => {
    let out
    try {
      // git grep searches tracked files only and needs no shell
      out = await $.process.run(['git', 'grep', '-n', '-I', '-E', 'TODO|FIXME'])
    } catch {
      return { text: 'Could not run git grep.' }
    }
    // git grep exits 1 when nothing matches
    if (out.exitCode === 1) return { text: 'No TODO or FIXME lines found.' }
    if (out.exitCode !== 0) return { text: 'git grep failed: ' + out.stderr.trim() }
    const lines = out.stdout.trim().split('\n')
    const shown = lines.slice(0, 20).join('\n')
    const more = lines.length > 20 ? '\n... and ' + (lines.length - 20) + ' more' : ''
    return { text: lines.length + ' TODO/FIXME lines:\n' + shown + more }
  })
}

يغطي اختباران حالة المطابقة وعدم المطابقة. في الواقع، في مستودع (repository) يحتوي على سطرين محددين، قام الأمر claude -p "/todos" --plugin-dir ./todo-scan بطباعة:

todo-scan: 2 TODO/FIXME lines:
app.js:2:// TODO handle empty input
app.js:3:// FIXME flaky retry

لم تكن هناك حاجة لاستدعاء النموذج. يضع Claude Code اسم الإضافة (plugin) أمام نص الأمر.4

انتبه للاسم الذي تختاره: تطلق $.command.register خطأً إذا كان هناك أمر مدمج يستخدم الاسم بالفعل، وأي هوك يطلق خطأً يتم تخطيه، لذا قم بتسجيل الأوامر في نهاية session.start أو غلفها بـ try.9

6. إظهار "إيصال" تحت كل إجابة: الوقت المستغرق والتوكنز المستخدمة

هذا مفيد إذا كنت تراقب المدة التي تستغرقها الأدوار أو تكلفة التوكنز.

يتم إطلاق turn.complete عند انتهاء الدور. يحمل الحدث durationMs، وusage للتوكنز في الدور، وisAborted، ويمكن للهوك إرجاع حقل text يظهر كسطر تحت الإجابة.5

export function register(on) {
  on('turn.complete', async ($, e, next) => {
    const result = await next(e)
    // Subagent turns and interrupted turns get no receipt
    if (e.agentId || e.isAborted) return result
    const seconds = (e.durationMs / 1000).toFixed(1)
    const tokens = e.usage ? ' · ' + e.usage.output_tokens + ' output tokens' : ''
    // A text other than the answer itself is shown under the answer
    return { ...result, text: 'Done in ' + seconds + 's' + tokens }
  })
}

يتحقق اختباران من السطر لدور استغرق 12,345 مللي ثانية مع 420 توكن مخرجات (Done in 12.3s · 420 output tokens) ومن أن الدور المقطوع لا يحصل على شيء. في تشغيل claude -p يتم طباعة الإجابة فقط، لذا يظهر هذا السطر في الجلسات التفاعلية.

يتخطى الهوك أدوار الوكلاء الفرعيين (subagent turns)، والتي تطلق أيضاً turn.complete مع تعيين agentId.5

7. رسم مقياس للسياق فوق الأمر

هذا مفيد عندما تريد رؤية نافذة السياق وهي تمتلئ قبل أن تكتمل.

الشريط الموجود فوق الأمر هو موقع رندر (render site) يتشاركه كل mod. يقوم هوك ui.render المفلتر إلى { component: 'AbovePrompt' } بإرجاع ما يجب رسمه هناك، أو next(e) لعدم رسم شيء.10 ترجع $.session.usage() توكنز نافذة السياق tokens، وwindow وpercent، من بين أرقام أخرى.6

// A 20-cell bar, filled in proportion to the percent used
function bar(percent) {
  const filled = Math.round(percent / 5)
  return '█'.repeat(filled) + '░'.repeat(20 - filled)
}

export function register(on) {
  // After each turn the context has grown, so ask for a redraw of the band
  on('turn.complete', async ($, e, next) => {
    const result = await next(e)
    $.ui.invalidate('ui.render')
    return result
  })

  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
    // Give way to a survey that wants the band
    if (e.props.hasSurvey) return next(e)
    const { context } = await $.session.usage()
    // No reading yet, before the first response
    if (context.percent === undefined) return next(e)
    const { Text } = $.ui.resolve(e)
    const color = context.percent >= 80 ? 'red' : context.percent >= 60 ? 'yellow' : 'green'
    const used = Math.round((context.tokens ?? 0) / 1000) + 'k of ' + Math.round(context.window / 1000) + 'k'
    return Text({ color, children: ['context ' + bar(context.percent) + ' ' + context.percent + '% (' + used + ')'] })
  })
}

الرسم يتغير فقط عندما يتم تشغيل الـ hook الخاص به مرة أخرى، لذا يقوم الـ mod باستدعاء $.ui.invalidate('ui.render') بعد كل دور.10

يقوم الاختبار الأول برسم الشريط باستخدام $.ui.mount على كل من أسطح الـ terminal والـ desktop. مع استخدام 84,000 من أصل 200,000 توكن، يقوم برسم context ████████░░░░░░░░░░░░ 42% (84k of 200k). أما الاختبار الثاني فيتحقق من عدم رسم أي شيء قبل القراءة الأولى.

يقوم Claude Code بتقليل سرعة إعادة الرسم إلى 10 مرات في الثانية، أو 30 في الـ terminal لبعض المواقع، وهو أكثر بكثير مما يحتاجه هذا المقياس.6

8. احتفظ بملاحظاتك المسودة في لوحة تصمد أمام إعادة التشغيل

إذا كنت تحتفظ بقائمة جارية من الأشياء التي يجب التحقق منها أثناء عمل Claude، فضعها في لوحة (pane).

يفتح /notes لوحة تحتوي على حقل نصي. تحصل كل ملاحظة على زر x لحذفها، ويتم حفظ القائمة في $.store، وهو مخزن مفتاح-قيمة (key-value store) يستمر بين الجلسات.10 يتبع هذا مثال الملاحظات الموجود في الوثائق، مع إضافة خاصية التحميل.

const PANE = 'scratch-notes'

// The notes the pane draws, loaded from the store when the session starts
let notes = []

export function register(on) {
  on('session.start', async ($, e, next) => {
    const saved = await $.store.get('notes')
    if (Array.isArray(saved)) notes = saved
    await $.command.register({ name: 'notes', description: 'Open your scratch notes pane' })
    return next(e)
  })

  on('command.run', { command: 'notes' }, async ($) => {
    await $.ui.open({ id: PANE, title: 'Notes', focus: true, closeOnEscape: true })
    // Print nothing in the transcript
    return {}
  })

  on('ui.render', { component: 'Pane' }, async ($, e, next) => {
    // Leave other mods' panes alone
    if (e.requestId !== PANE) return next(e)
    const { Box, Text, Button, Input } = $.ui.resolve(e)
    const save = async () => {
      $.ui.invalidate('ui.render')
      await $.store.set('notes', notes)
    }
    return Box({
      flexDirection: 'column',
      children: [
        Input({
          key: 'new-note',
          label: 'Note',
          placeholder: 'Type a note and press Enter',
          value: '',
          submitLabel: 'add',
          autoFocus: true,
          onSubmit: async (value) => {
            if (!value.trim()) return
            notes = [...notes, value.trim()]
            await save()
          },
        }),
        ...notes.map((note, i) =>
          Box({
            flexDirection: 'row',
            columnGap: 1,
            children: [
              Button({
                key: 'delete-' + i,
                label: 'x',
                plain: true,
                onPress: async () => {
                  notes = notes.filter((_, j) => j !== i)
                  await save()
                },
              }),
              Text({ children: [note] }),
            ],
          }),
        ),
      ],
    })
  })
}

يقوم الاختبار الأول بكتابة ملاحظة، والتحقق من رسمها، ثم حذفها، والتحقق من القائمة المحفوظة على كل من أسطح الـ terminal والـ desktop. ويتحقق اختبار ثانٍ من أن الملاحظات المحفوظة مسبقاً تعود بعد session.start.

ضع في اعتبارك أن $.store مشترك بين كل جلسة على جهازك، وعملية get متبوعة بـ set ليست ذرية (atomic)، لذا يمكن لجلساتين أن تمسح تغييرات بعضهما البعض.10 يتسع المخزن لما يصل إلى 4 ميجابايت من JSON.6

9. امنح Claude أداة مخصصة دون تشغيل خادم MCP

غالباً ما ترغب الفرق في أن يقوم Claude بالبحث عن شيء ما في أحد أنظمتهم الخاصة.

يضيف $.tool.register أداة يمكن لـ Claude استدعاؤها. يراها Claude تحت اسم أطول، mcp__<plugin>__<tool>، ويقوم الـ tool.call hook الخاص بك لهذا الاسم الكامل بالرد عليه.9

هذه الأداة تجلب مشكلة (issue) من GitHub. تقول وثائق REST الخاصة بـ GitHub إن الطلبات التي لا تحتوي على ترويسة User-Agent يتم رفضها، ولهذا السبب يرسل الـ mod واحدة.11 هناك متغير بيئة اختياري TICKET_API_BASE، يتم قراءته بواسطة $.env.get، يوجه الأداة نحو GitHub Enterprise أو خادم اختبار.9

export function register(on) {
  on('session.start', async ($, e, next) => {
    await $.tool.register({
      name: 'github_issue',
      // Claude decides when to call the tool from this description
      description: 'Look up a GitHub issue or pull request and return its title, state, labels and first 1,500 characters',
      inputSchema: {
        type: 'object',
        properties: {
          repo: { type: 'string', description: 'owner/name, such as anthropics/claude-code' },
          number: { type: 'integer' },
        },
        required: ['repo', 'number'],
      },
    })
    return next(e)
  })

  // The full name is mcp__, the plugin's name, two underscores, and the tool's name
  on('tool.call', { tool: 'mcp__ticket-tool__github_issue' }, async ($, e) => {
    if (!/^[\w.-]+\/[\w.-]+$/.test(e.repo)) return { result: 'repo must look like owner/name' }
    // GitHub by default; set TICKET_API_BASE to point at GitHub Enterprise or a test server
    const base = (await $.env.get('TICKET_API_BASE')) ?? 'https://api.github.com'
    const url = base + '/repos/' + e.repo + '/issues/' + Number(e.number)
    const response = await $.http.fetch(url, { headers: { accept: 'application/vnd.github+json', 'user-agent': 'ticket-tool-mod' } })
    if (!response.ok) return { result: 'Lookup failed with status ' + response.status }
    let issue
    try {
      issue = JSON.parse(response.text)
    } catch {
      return { result: 'The lookup returned something that is not JSON' }
    }
    const labels = (issue.labels ?? []).map((l) => l.name).join(', ') || 'none'
    return {
      result: '#' + issue.number + ' ' + issue.title + '\nstate: ' + issue.state + '\nlabels: ' + labels + '\n\n' + (issue.body ?? '').slice(0, 1500),
    }
  }).catch(async ($, e, next) => {
    // A network error or a timeout becomes a result Claude can read
    return { result: 'The issue lookup failed: ' + next.error.kind }
  })
}

يقوم اختباران بعمل stub لـ $.http.fetch: أحدهما يتحقق من رابط GitHub والملخص لمشكلة تم العثور عليها، والآخر يتحقق من أن TICKET_API_BASE يغير الرابط وأنه يتم الإبلاغ عن خطأ 404.

أول تشغيل حي لنا ضد api.github.com أعطى HTTP 403، لأن بروكسي الشبكة الخاص بالـ sandbox يسمح فقط باستدعاءات GitHub API للمستودعات المرتبطة بالجلسة.

لذا قمنا بتشغيله حياً ضد خادم محلي صغير يستجيب مثل نقطة نهاية المشكلات (issues endpoint) في GitHub. استدعى Claude الأداة ورد بالعنوان والحالة والتصنيفات التي أرسلها الخادم (Export button does nothing, open, bug, p1)، وأظهر سجل الخادم الطلب مع User-Agent الخاص بالـ mod.

يسمح GitHub بمزيد من الطلبات في الساعة عند المصادقة.11 بالنسبة للمستودعات الخاصة، اقرأ رمز الوصول (token) باستخدام $.env.get وأرسله كـ header.9

10. مراقبة CI وعرض النتيجة أسفل الأمر (prompt)

تساعد هذه الإضافة أثناء انتظارك لعمليات التحقق من الـ pull request مع الاستمرار في العمل.

العمل الذي يستمر لأكثر من حدث واحد يعمل على مؤقت يبدأ في session.start. ويحل $.clock.every محل setInterval، بينما يقوم $.ui.status بتعيين سطر واحد أسفل الأمر يظل موجوداً حتى تقوم بتغييره.9

تطلب هذه الإضافة من GitHub CLI التحقق من حالة الـ pull request الحالية مرة كل دقيقة. يتضمن gh pr checks --json حقلاً باسم bucket يصنف كل عملية تحقق إلى pass، أو fail، أو pending، أو skipping أو cancel.12

// Turn gh's JSON into a short line such as "3 pass · 1 fail · 2 pending"
function summarize(json) {
  const counts = {}
  for (const check of JSON.parse(json)) counts[check.bucket] = (counts[check.bucket] ?? 0) + 1
  const parts = ['pass', 'fail', 'pending'].filter((b) => counts[b]).map((b) => counts[b] + ' ' + b)
  return parts.length > 0 ? parts.join(' · ') : 'no checks'
}

async function refresh($) {
  let out
  try {
    out = await $.process.run(['gh', 'pr', 'checks', '--json', 'bucket,name'])
  } catch {
    $.ui.status(undefined)
    return
  }
  // gh exits 8 while checks are pending and 1 when the command fails,
  // so read the JSON instead of the exit code
  let line
  try {
    line = 'CI: ' + summarize(out.stdout)
  } catch {
    line = undefined
  }
  // undefined clears the line
  $.ui.status(line)
}

export function register(on) {
  on('session.start', async ($, e, next) => {
    // Check once a minute; the timer stops when the mod reloads
    $.clock.every(60_000, () => refresh($))
    return next(e)
  })
}

يستخدم اختباران mock.clock الخاص بالمجموعة، لذا تمر الدقيقة فوراً. بعد 59 ثانية لا يظهر شيء. وعند 60 ثانية يقرأ السطر CI: 2 pass · 1 pending. وعندما لا يكون هناك pull request، يتم مسح السطر.

تتوقف المؤقتات عند إعادة تحميل الإضافة، ويبدأ مثيل (instance) جديد مؤقته الخاص.910 يبدأ سطر الحالة بعلامة تحذير واسم الإضافة، لذا اجعل النص قصيراً.9

ما الذي تغير في الأسبوع الأول

وصلت الإضافات (Mods) في الإصدار 2.1.287 في 1 أكتوبر 2026، وتبع ذلك ثمانية إصدارات أخرى بحلول 8 أكتوبر.2 هناك بعض التغييرات التي تهم مؤلفي الإضافات:

الإصدارالتاريخالتغيير
2.1.2871 أكتوبر 2026"إضافة Claude Mods: يمكن للإضافات الآن تعديل سلوكيات أعمق"
2.1.2882 أكتوبر 2026إضافة $.ui.selection()، والتي تعيد النص الذي حددته مؤخراً في وضع ملء الشاشة
2.1.2905 أكتوبر 2026يقوم claude plugin validate بسرد كل hook مسجل في موقع gating، وما إذا كان يحتوي على .catch
2.1.2926 أكتوبر 2026تخزين مؤقت للأوامر (Prompt caching) لـ $.model.complete، وحدث prompt.autocomplete جديد
2.1.2937 أكتوبر 2026إضافة isDeferred في $.tool.register، لسرد مخطط الأداة (tool's schema) في الأمر منذ البداية
2.1.2958 أكتوبر 2026إضافة $.ui.notify؛ الرفض بعد تشغيل الأداة يقول الآن "تم تشغيل الأداة وقامت إضافة بحجب نتيجتها"

المصدر: سجل تغييرات Claude Code.2 تغيير الإصدار 2.1.290 هو السبب في أن مخرجات validate لدينا تتضمن أسطراً مثل gating hook with .catch: tool.call{tool=Bash}، وهو ما لا تظهره مخرجات الأمثلة في التوثيق بعد. يحذر التوثيق من أن الأحداث والطرق قد تتغير بين الإصدارات، وأن تعريفات الأنواع التي يكتبها Claude Code لإصدارك هي المرجع الأدق في حال وجود تعارض مع أي صفحة توثيق.4

الأخطاء الشائعة والقيود

claude plugin validate يقرأ الكود المصدري الخاص بك بنفس الطريقة التي يقوم بها Claude Code، ومعظم الأخطاء الأولى تأتي من قواعده:4

  • اكتب كل استدعاء API بالكامل، كما في $.store.get('notes'). استدعاء const ui = $.ui سيفشل مع خطأ $.ui is used as a value.
  • استخدم نصاً صريحاً (string literal) لاسم الحدث. استخدام متغير أو حلقة تكرارية (loop) على الأسماء سيؤدي لفشل التحقق.
  • سجل كل حدث مرة واحدة لكل matcher. وجود اثنين من خطافات (hooks) session.start بدون matcher يمنع تحميل الموديول.5
  • استخدم ES modules. لا تستخدم require، ولا استدعاءات import().4

القيود الأكثر شيوعاً:6

القيدالقيمة
وقت تشغيل الخطاف (hook) لحدث واحد10 ثوانٍ
معالج .catchثانية واحدة
مهلة $.process.run30 ثانية افتراضياً، 10 دقائق كحد أقصى
maxTokens في $.model.complete1,024 افتراضياً
$.fs.read و $.fs.write4 ميجابايت لكل ملف
$.store4 ميجابايت من JSON إجمالاً
اختبار claude plugin test واحد5 ثوانٍ ما لم يتم تعيين timeoutMs

الوقت الذي يتم قضاؤه في الانتظار داخل next أو استدعاء API للمودز لا يُحتسب ضمن الـ 10 ثوانٍ، باستثناء $.clock.sleep.6 وهذا هو السبب في أن حارس confirm-risky يمكنه الانتظار على $.ui.ask دون تجاوز الحد.5

هل مودز Claude Code آمنة؟

المودز تكون آمنة بقدر أمان مؤلفها. تقول الوثائق أن المود "يعمل بصلاحياتك": يمكنه قراءة وكتابة ملفاتك، وبدء البرامج، وإجراء طلبات الشبكة، وقراءة متغيرات البيئة الخاصة بك، ورؤية كل أمر (prompt) واستدعاء أداة، والموافقة على استدعاء أداة قبل أن يُطلب منك ذلك، واستدعاء نموذج (model) ضمن خطتك. "المودز ليست معزولة (sandboxed)". وحتى مع تفعيل العزل، فإن أي عملية يبدأها المود تعمل خارج نطاق العزل.3

هناك شيئان لا يمكن للمود القيام بهما: تغيير ما يظهر في مطالبة الصلاحيات، أو تجاوز حظر من خطاف PreToolUse في إعدادات الإدارة الخاصة بمؤسستك، والتي تعمل قبل أي مود.35

قبل تثبيت مود خاص بشخص آخر، قم بتشغيل claude plugin validate على المجلد الخاص به. ستعرض أسطر hooks: و calls: الأحداث التي يتعامل معها وكل استدعاء API يقوم به، دون تشغيله.3 يغطي تحليلنا في Plugin4Shell سبب أهمية الثقة في الإضافات بالنسبة لوكلاء البرمجة.

لإيقاف تشغيل الـ mods: قم بتعطيل أحدها في /plugin، أو ابدأ جلسة باستخدام --safe-mode، أو قم بتعيين "disableAllHooks": true في ~/.claude/settings.json.3

عناصر التحكم للفرق والمؤسسات

في خطط Team و Enterprise، وعلى الأجهزة ذات الإعدادات المدارة، يتم تحميل حارس مدمج يسمى sec-default قبل الـ mods التي يثبتها المستخدم، لمنعهم من القيام بأشياء خطيرة مثل تجاوز قواعد رفض الأذونات.16 يمكن للمسؤولين أيضاً:6

  • تشغيل الـ mods الخاصة بهم أولاً أو أخيراً باستخدام prependPlugins و appendPlugins
  • السماح فقط بـ mods المؤسسة باستخدام allowManagedModsOnly
  • رفض --plugin-dir و --plugin-url عند بدء التشغيل باستخدام disableSideloadFlags

تتضمن أمثلة فريق الإعلان نفسها حالة CI/CD في لوحة جانبية، وتأكيداً قبل أن تؤثر الأوامر على إعدادات الإنتاج (production config)، وسجلاً تدقيقياً لكل استدعاءات الـ mod.1

أين تعمل الـ mods؟

ترتبط الـ mods بالأحداث في كل مكان يتم فيه تحميل الإضافة، لكنها ترسم فقط في بعض الأماكن.3

مكان تشغيل Claude Codeتشغيل الـ Hooksظهور الرسومات
claude في Terminalنعمنعم
تبويب Code في تطبيق Desktop (ليس جلسات WSL)نعمنعم، باستثناء عناصر الـ terminal فقط
لوحة الدردشة في إضافة VS Codeنعملا
claude -p و Agent SDKنعملا
جلسة سحابية (cloud session)نعم، إذا وصلت الإضافة إليهالا

لهذا السبب أمكن اختبار ستة من الـ mods الخاصة بنا مباشرة في claude -p بينما لم يكن ذلك ممكناً للـ mods التي تعتمد على الرسم.

أماكن إضافية للبدء

  • الـ mods المدمجة. بعض ميزات Claude Code نفسها هي عبارة عن mods، مثل /diff، ويمكنك رؤيتها تحت قسم Built-in في /plugin. يوجد مصدر العديد منها في مجلد mods الخاص بمستودع Claude Code.3
  • نماذج Anthropic. يحتوي مستودع claude-code-playground على token-weather (توقعات للسياق فوق المطالبة)، و blast-radius (يحتجز الأمر الخطير ويظهر ما سيقوم بتغييره)، و replay-theater (أمر /replay لتعديلات الدورة الأخيرة). تشارك Anthropic هذه النماذج كما هي، بدون دعم.3
  • اسأل Claude. صف الـ mod الذي تريده، وسيقوم Claude بكتابته باستخدام مهارة plugin-authoring. سيعمل بمجرد موافقتك عليه.4

الخلاصة

يمكنك الآن تغيير طريقة سلوك Claude Code ببضع عشرات من أسطر JavaScript. تغطي الأمثلة العشرة هنا المهام الشائعة: حماية أمر ما، تغيير ما يقرأه Claude، إضافة أمر أو أداة، ورسم حالة خاصة بك. كل مثال منها قصير، ويسمح لك claude plugin test بإثبات عمله قبل أن يلمس جلسة حقيقية. اقرأ أي إضافة لم تكتبها بنفسك قبل تحميلها، لأنها تعمل بصلاحياتك.

المراجع

Footnotes

  1. Customize Claude Code with mods, Anthropic, October 1, 2026. Source for "small TypeScript functions", what a mod can do with one function including redacting secrets from tool output, /diff shipping as a mod, sec-default on Team and Enterprise plans, the team examples, and the warning that mods aren't sandboxed. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  2. Claude Code changelog, Anthropic, versions 2.1.287 (October 1, 2026) to 2.1.295 (October 8, 2026), read October 9, 2026. ↩ ↩2 ↩3 ↩4

  3. Mods overview, Claude Code docs, read October 9, 2026. Source for the definition, version requirements, the comparison table, what a mod can reach, the permission prompt, where mods run, turning mods off, built-in mods and the sample mods. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18 ↩19

  4. Create a mod, Claude Code docs, read October 9, 2026. Source for the three files, no build step, --plugin-dir, the plugin-authoring skill, claude plugin validate and its rules, and the advice to trust the type declarations for your version. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11

  5. React to events with a mod, Claude Code docs, read October 9, 2026. Source for observe, rewrite and answer, tool.call, $.ui.ask, tool.check, prompt.submit context, turn.complete, managed PreToolUse hooks running first, failing hooks and .catch. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11

  6. Mods reference, Claude Code docs, read October 9, 2026. Source for files, $.session.usage(), limits, render sites and organization settings. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  7. Test a mod, Claude Code docs, read October 9, 2026. Source for claude plugin test, stubs, mock.clock, $.ui.mount and the exit status. ↩ ↩2 ↩3 ↩4

  8. Claude Code 2.1.295 type declarations for mods, ToolCallResult, the file Claude Code writes beside a mod as .claude-plugin/types/claude-code/index.d.ts. A published copy lives at mods/types/claude-code.d.ts in the Claude Code repository and can be older than your version. ↩

  9. Use the mods API, Claude Code docs, read October 9, 2026. Source for commands, immediate, tools and their mcp__ names, $.clock, $.ui.status, $.ui.log and $.env. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  10. Draw in the interface with a mod, Claude Code docs, read October 9, 2026. Source for render sites, the band above the prompt, panes, the notes example, redraws and $.store. ↩ ↩2 ↩3 ↩4 ↩5

  11. Getting started with the REST API, GitHub Docs, read October 9, 2026. Source for the required User-Agent header and higher hourly limits for authenticated requests. ↩ ↩2

  12. gh pr checks, GitHub CLI manual, read October 9, 2026. Source for the --json fields and the bucket values. ↩

الأسئلة الشائعة

تعد إضافات (mods) Claude Code بمثابة ملحقات تحتوي على وظائف JavaScript أو TypeScript يستدعيها Claude Code عند وقوع حدث ما، مثل استدعاء أداة، أو مطالبة (prompt)، أو إعادة رسم الواجهة. يمكن للإضافة مراقبة الحدث، أو إعادة كتابته، أو الرد عليه، كما يمكنها رسم ألواح (panes)، وأشرطة (bands)، وخطوط حالة. أضافتها Anthropic في الإصدار 2.1.287 في 1 أكتوبر 2026.123