דלג לתוכן הראשי
מדיניויות מותאמות מאפשרות לך לכתוב כללים לכל התנהגות agent: אכוף קונבנציות פרויקט, עצור drift, שער פעולות הורסות, גלה agents תקועות, או התחבר ל-Slack, תהליכי אישור, ועוד. הם משתמשים באותה מערכת hook event ובהחלטות 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 hooks: שים קובץ, זה פשוט עובד.
# 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
איך זה עובד:
  • שתי התיקיות של פרויקט ומשתמש סורקות (union — לא 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. הקובץ נטען מחדש בכל hook event - אין cache בין events.

שימוש בשניהם ביחד

מדיניויות קונבנציה והקובץ --custom המפורש יכולים להתקיים. סדר הטעינה:
  1. קובץ customPoliciesPath מפורש (אם מוגדר)
  2. קבצי קונבנציה של פרויקט ({cwd}/.failproofai/policies/, אלפביתי)
  3. קבצי קונבנציה של משתמש (~/.failproofai/policies/, אלפביתי)

API

Import

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)חסום את הפעולהל-agent אין לבצע פעולה זו
instruct(message)הוסף הקשר ללא חסימהתן ל-agent הקשר נוסף להישאר בעקבות
deny(message) - ההודעה מופיעה ל-Claude בתחילית "Blocked by failproofai:". deny אחד בודד מקצר את כל ההערכה הנוספת. instruct(message) - ההודעה מצורפת להקשר של Claude לקריאת הכלי הנוכחית. כל הודעות instruct מצטברות ומועברות יחד.
אתה יכול להצמיד הנחיות נוספות לכל הודעת deny או instruct על ידי הוספת שדה hint ב-policyParams — ללא צורך בשינוי קוד. זה עובד גם על מדיניויות custom (custom/), קונבנציה של פרויקט (.failproofai-project/), וקונבנציה של משתמש (.failproofai-user/). ראה Configuration → hint לפרטים.

הודעות allow מידע

allow(message) מתיר את הפעולה ושולח הודעה מידע בחזרה ל-Claude. ההודעה מועברת כ-additionalContext בתגובת stdout של hook handler — אותה מנגנון שבו משתמשים 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

שדהסוגתיאור
eventTypestring"PreToolUse", "PostToolUse", "Notification", "Stop"
toolNamestring | undefinedהכלי שנקרא (למשל "Bash", "Write", "Read")
toolInputRecord<string, unknown> | undefinedפרמטרי הקלט של הכלי
payloadRecord<string, unknown>payload אירוע גולמי מלא מ-Claude Code
sessionSessionMetadata | undefinedהקשר סשן (ראה למטה)

שדות SessionMetadata

שדהסוגתיאור
sessionIdstringמזהה סשן Claude Code
cwdstringספריית עבודה של סשן Claude Code
transcriptPathstringנתיב לקובץ תמליל JSONL של הסשן

סוגי אירוע

אירועמתי הוא משדרתוכן toolInput
PreToolUseלפני ש-Claude מריץ כליקלט הכלי (למשל { command: "..." } עבור Bash)
PostToolUseלאחר סיום כליקלט הכלי + tool_result (הפלט)
Notificationכאשר Claude שולח הודעה{ message: "...", notification_type: "idle" | "permission_prompt" | ... } - hooks חייבים תמיד להחזיר allow(), הם לא יכולים לחסום הודעות
Stopכאשר סשן Claude מסתייםריק

סדר הערכה

מדיניויות מוערכות בסדר זה:
  1. מדיניויות מובנות (בסדר הגדרה)
  2. מדיניויות custom מפורשות מ-customPoliciesPath (בסדר .add())
  3. מדיניויות קונבנציה מ-.failproofai/policies/ של פרויקט (קבצים אלפביתיים, סדר .add() בתוך)
  4. מדיניויות קונבנציה מ-~/.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: שגיאות לעולם לא חוסמות מדיניויות מובנות או מקרסות hook handler.
כשלהתנהגות
customPoliciesPath לא מוגדראין מדיניויות custom מפורשות פועלות; מדיניויות קונבנציה ומובנות ממשיכות בדרך כלל
קובץ לא נמצאאזהרה מתועדת ל-~/.failproofai/hook.log; מובנים ממשיכים
שגיאת Syntax/import (מפורשת)שגיאה מתועדת ל-~/.failproofai/hook.log; מדיניויות custom מפורשות דולגות
שגיאת Syntax/import (קונבנציה)שגיאה מתועדת; קובץ זה דולג, קבצי קונבנציה אחרים עדיין נטענים
fn זורק בזמן ריצהשגיאה מתועדת; hook זה מטופל כ-allow; hooks אחרים ממשיכים
fn לוקח יותר מ-10 שניותtimeout מתועדת; מטופל כ-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חמש מדיניויות קלפי סטרטר המכסות מצבי כשל נפוצים של agent
examples/policies-advanced/index.jsדפוסים מתקדמים: ייבואים טרנזיטיביים, קריאות async, ניקוי פלט, hooks של סוף סשן
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/
לא נדרש פקודת התקנה — הקבצים נקטפים באופן אוטומטי בהאירוע hook הבא.