title: السياسات المخصصة
description: “اكتب سياساتك الخاصة في JavaScript - فرض الاتفاقيات، منع الانجراف، الكشف عن الأعطال، التكامل مع الأنظمة الخارجية”
icon: code
تتيح لك السياسات المخصصة كتابة قواعد لأي سلوك وكيل: فرض اتفاقيات المشروع، منع الانجراف، التحكم في العمليات الضارة، الكشف عن الوكلاء المعلقة، أو التكامل مع Slack وسير العمل الموافقات والمزيد. تستخدم نفس نظام حدث الخطاف وقرارات allow و deny و instruct كما هو الحال في السياسات المدمجة.
مثال سريع
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";
customPolicies.add({
name: "no-production-writes",
description: "Block writes to paths containing 'production'",
match: { events: ["PreToolUse"] },
fn: async (ctx) => {
if (ctx.toolName !== "Write" && ctx.toolName !== "Edit") return allow();
const path = ctx.toolInput?.file_path ?? "";
if (path.includes("production")) {
return deny("Writes to production paths are blocked");
}
return allow();
},
});
تثبيتها:
failproofai policies --install --custom ./my-policies.js
طريقتان لتحميل السياسات المخصصة
الخيار 1: المبنية على الاتفاقية (موصى به)
أسقط ملفات *policies.{js,mjs,ts} في .failproofai/policies/ وسيتم تحميلها تلقائياً - لا تحتاج إلى أعلام أو تغييرات في الإعدادات. يعمل هذا مثل خطافات git: أسقط ملفاً، وهو يعمل فقط.
# Project level — committed to git, shared with the team
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs
# User level — personal, applies to all projects
~/.failproofai/policies/my-policies.mjs
كيفية عمله:
- يتم فحص كلا المجلدات (المشروع والمستخدم) (الاتحاد - وليس first-scope-wins)
- يتم تحميل الملفات أبجدياً في كل مجلد. اجعل البادئة
01- أو 02- للتحكم في الترتيب
- يتم تحميل الملفات المطابقة
*policies.{js,mjs,ts} فقط؛ يتم تجاهل الملفات الأخرى
- يتم تحميل كل ملف بشكل مستقل (fail-open لكل ملف)
- يعمل جنباً إلى جنب مع السياسات الصريحة
--custom والمدمجة
سياسات الاتفاقية هي أسهل طريقة لمشاركة السياسات عبر الفريق. التزم .failproofai/policies/ بـ git ويحصل كل عضو في الفريق عليها تلقائياً.
الخيار 2: مسار الملف الصريح
# Install with a custom policies file
failproofai policies --install --custom ./my-policies.js
# Replace the policies file path
failproofai policies --install --custom ./new-policies.js
# Remove the custom policies path from config
failproofai policies --uninstall --custom
يتم حفظ المسار المطلق المُحل في policies-config.json كـ customPoliciesPath. يتم تحميل الملف بشكل جديد في كل حدث خطاف - لا يوجد تخزين مؤقت بين الأحداث.
استخدام كليهما معاً
يمكن لسياسات الاتفاقية والملف الصريح --custom أن يتعايشا. ترتيب التحميل:
- ملف
customPoliciesPath الصريح (إذا تم تكوينه)
- ملفات اتفاقية المشروع (
{cwd}/.failproofai/policies/، أبجدياً)
- ملفات اتفاقية المستخدم (
~/.failproofai/policies/، أبجدياً)
واجهة برمجية التطبيقات
الاستيراد
import { customPolicies, allow, deny, instruct } from "failproofai";
customPolicies.add(hook)
تسجيل سياسة. اتصل بها عدة مرات حسب الحاجة لسياسات متعددة في نفس الملف.
customPolicies.add({
name: string; // required - unique identifier
description?: string; // shown in `failproofai policies` output
match?: { events?: HookEventType[] }; // filter by event type; omit to match all
fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});
مساعدو القرار
| الدالة | التأثير | استخدم عندما |
|---|
allow() | السماح بالعملية بصمت | الإجراء آمن، لا توجد رسالة مطلوبة |
deny(message) | حظر العملية | يجب ألا يتخذ الوكيل هذا الإجراء |
instruct(message) | إضافة سياق دون حظر | إعطاء الوكيل سياق إضافي للبقاء على المسار |
deny(message) - تظهر الرسالة إلى Claude بسابقة "Blocked by failproofai:". يقطع deny واحد كل تقييم آخر.
instruct(message) - يتم إلحاق الرسالة بسياق Claude لاستدعاء الأداة الحالي. يتم تجميع جميع رسائل instruct وتسليمها معاً.
يمكنك إلحاق إرشادات إضافية بأي رسالة deny أو instruct بإضافة حقل hint في policyParams - لا حاجة لتغيير الرمز. يعمل هذا أيضاً للسياسات المخصصة (custom/)، واتفاقية المشروع (.failproofai-project/)، واتفاقية المستخدم (.failproofai-user/). انظر التكوين → hint للتفاصيل.
رسائل السماح المعلوماتية
allow(message) يسمح بالعملية و يرسل رسالة معلومات مرة أخرى إلى Claude. يتم تسليم الرسالة كـ additionalContext في استجابة stdout لمعالج الخطاف - نفس الآلية المستخدمة من قبل instruct، لكن مختلفة من الناحية الدلالية: إنها تحديث حالة وليست تحذير.
| الدالة | التأثير | استخدم عندما |
|---|
allow(message) | السماح وإرسال السياق إلى Claude | تأكيد نجاح الفحص، أو شرح سبب تخطي الفحص |
حالات الاستخدام:
- تأكيدات الحالة:
allow("All CI checks passed.") - يخبر Claude أن كل شيء أخضر
- شروحات fail-open:
allow("GitHub CLI not installed, skipping CI check.") - يخبر Claude سبب تخطي الفحص حتى يكون لديه السياق الكامل
- تراكم الرسائل المتعددة: إذا أرجعت عدة سياسات
allow(message)، يتم ربط جميع الرسائل بخطوط جديدة وتسليمها معاً
customPolicies.add({
name: "confirm-branch-status",
match: { events: ["Stop"] },
fn: async (ctx) => {
const cwd = ctx.session?.cwd;
if (!cwd) return allow("No working directory, skipping branch check.");
// ... check branch status ...
if (allPushed) {
return allow("Branch is up to date with remote.");
}
return deny("Unpushed changes detected.");
},
});
حقول PolicyContext
| الحقل | النوع | الوصف |
|---|
eventType | string | "PreToolUse"، "PostToolUse"، "Notification"، "Stop" |
toolName | string | undefined | الأداة التي يتم استدعاؤها (مثل "Bash"، "Write"، "Read") |
toolInput | Record<string, unknown> | undefined | معاملات إدخال الأداة |
payload | Record<string, unknown> | حمل الحدث الخام الكامل من Claude Code |
session | SessionMetadata | undefined | سياق الجلسة (انظر أدناه) |
| الحقل | النوع | الوصف |
|---|
sessionId | string | معرّف جلسة Claude Code |
cwd | string | دليل العمل لجلسة Claude Code |
transcriptPath | string | المسار إلى ملف النسخة JSONL الخاص بالجلسة |
أنواع الأحداث
| الحدث | متى يتم تشغيله | محتويات toolInput |
|---|
PreToolUse | قبل تشغيل Claude لأداة | إدخال الأداة (مثل { command: "..." } لـ Bash) |
PostToolUse | بعد اكتمال الأداة | إدخال الأداة + tool_result (الإخراج) |
Notification | عندما يرسل Claude إشعاراً | { message: "...", notification_type: "idle" | "permission_prompt" | ... } - يجب أن تعيد الخطافات دائماً allow()، فلا يمكنها حظر الإشعارات |
Stop | عند انتهاء جلسة Claude | فارغة |
ترتيب التقييم
يتم تقييم السياسات بهذا الترتيب:
- السياسات المدمجة (بترتيب التعريف)
- السياسات المخصصة الصريحة من
customPoliciesPath (بترتيب .add())
- سياسات الاتفاقية من
.failproofai/policies/ للمشروع (ملفات أبجدياً، ترتيب .add() بداخلها)
- سياسات الاتفاقية من
~/.failproofai/policies/ للمستخدم (ملفات أبجدياً، ترتيب .add() بداخلها)
يقطع أول deny جميع السياسات اللاحقة. يتم تجميع جميع رسائل instruct وتسليمها معاً.
الواردات المتعدية
يمكن لملفات السياسة المخصصة استيراد الوحدات المحلية باستخدام المسارات النسبية:
// my-policies.js
import { isBlockedPath } from "./utils.js";
import { checkApproval } from "./approval-client.js";
customPolicies.add({
name: "approval-gate",
fn: async (ctx) => {
if (ctx.toolName !== "Bash") return allow();
const approved = await checkApproval(ctx.toolInput?.command, ctx.session?.sessionId);
return approved ? allow() : deny("Approval required for this command");
},
});
يتم حل جميع الواردات النسبية الممكنة من ملف الإدخال. يتم تطبيق هذا بإعادة كتابة واردات from "failproofai" إلى مسار dist الفعلي وإنشاء ملفات .mjs مؤقتة لضمان توافق ESM.
تصفية نوع الحدث
استخدم match.events لتحديد متى يتم تشغيل سياسة:
customPolicies.add({
name: "require-summary-on-stop",
match: { events: ["Stop"] },
fn: async (ctx) => {
// Only fires when the session ends
// ctx.session.transcriptPath contains the full session log
return allow();
},
});
حذف match بالكامل للتشغيل في كل نوع حدث.
معالجة الأخطاء وأوضاع الفشل
السياسات المخصصة هي fail-open: الأخطاء لا تحظر السياسات المدمجة أو تعطل معالج الخطاف.
| الفشل | السلوك |
|---|
customPoliciesPath لم تُعيّن | لا تعمل السياسات المخصصة الصريحة؛ سياسات الاتفاقية والمدمجة تستمر بشكل طبيعي |
| ملف غير موجود | تم تسجيل تحذير في ~/.failproofai/hook.log؛ المدمجة تستمر |
| خطأ في الصيغة/الاستيراد (صريح) | تم تسجيل الخطأ في ~/.failproofai/hook.log؛ سياسات مخصصة صريحة تم تخطيها |
| خطأ في الصيغة/الاستيراد (اتفاقية) | تم تسجيل الخطأ؛ هذا الملف تم تخطيه، ملفات اتفاقية أخرى لا تزال تحمل |
fn رمي في وقت التشغيل | تم تسجيل الخطأ؛ تم التعامل مع الخطاف كـ allow؛ الخطافات الأخرى تستمر |
fn يستغرق أكثر من 10 ثوان | تم تسجيل المهلة الزمنية؛ تم التعامل معها كـ allow |
| مجلد الاتفاقية مفقود | لا تعمل سياسات الاتفاقية؛ لا خطأ |
لتصحيح أخطاء السياسة المخصصة، راقب ملف السجل:tail -f ~/.failproofai/hook.log
مثال كامل: سياسات متعددة
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";
// Prevent agent from writing to secrets/ directory
customPolicies.add({
name: "block-secrets-dir",
description: "Prevent agent from writing to secrets/ directory",
match: { events: ["PreToolUse"] },
fn: async (ctx) => {
if (!["Write", "Edit"].includes(ctx.toolName ?? "")) return allow();
const path = ctx.toolInput?.file_path ?? "";
if (path.includes("secrets/")) return deny("Writing to secrets/ is not permitted");
return allow();
},
});
// Keep the agent on track: verify tests before committing
customPolicies.add({
name: "remind-test-before-commit",
description: "Keep the agent on track: verify tests pass before committing",
match: { events: ["PreToolUse"] },
fn: async (ctx) => {
if (ctx.toolName !== "Bash") return allow();
const cmd = ctx.toolInput?.command ?? "";
if (/git\s+commit/.test(cmd)) {
return instruct("Verify all tests pass before committing. Run `bun test` if you haven't already.");
}
return allow();
},
});
// Prevent unplanned dependency changes during freeze
customPolicies.add({
name: "dependency-freeze",
description: "Prevent unplanned dependency changes during freeze period",
match: { events: ["PreToolUse"] },
fn: async (ctx) => {
if (ctx.toolName !== "Bash") return allow();
const cmd = ctx.toolInput?.command ?? "";
const isInstall = /^(npm install|yarn add|bun add|pnpm add)\s+\S/.test(cmd);
if (isInstall && process.env.DEPENDENCY_FREEZE === "1") {
return deny("Package installs are frozen. Unset DEPENDENCY_FREEZE to allow.");
}
return allow();
},
});
export { customPolicies };
أمثلة
يحتوي دليل examples/ على ملفات السياسات الجاهزة للتشغيل:
| الملف | المحتوى |
|---|
examples/policies-basic.js | خمس سياسات للمبتدئين تغطي أوضاع فشل الوكيل الشائعة |
examples/policies-advanced/index.js | أنماط متقدمة: واردات متعدية، استدعاءات غير متزامنة، تنقية الإخراج، وخطافات نهاية الجلسة |
examples/convention-policies/security-policies.mjs | سياسات الأمان المبنية على الاتفاقية (حظر كتابة .env، منع إعادة كتابة سجل git) |
examples/convention-policies/workflow-policies.mjs | سياسات سير العمل المبنية على الاتفاقية (تذكيرات الاختبار، ملفات التدقيق) |
استخدام أمثلة الملفات الصريحة
failproofai policies --install --custom ./examples/policies-basic.js
استخدام أمثلة الاتفاقية
# Copy to project level
mkdir -p .failproofai/policies
cp examples/convention-policies/*.mjs .failproofai/policies/
# Or copy to user level
mkdir -p ~/.failproofai/policies
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
لا حاجة لأمر التثبيت - يتم اختيار الملفات تلقائياً عند حدث الخطاف التالي.