Các chính sách tùy chỉnh cho phép bạn viết các quy tắc cho bất kỳ hành vi nào của agent: thực thi quy ước dự án, ngăn chặn sự trôi dạt, kiểm soát các hoạt động phá hủy, phát hiện các agent bị mắc kẹt, hoặc tích hợp với Slack, quy trình phê duyệt, v.v. Chúng sử dụng cùng một hệ thống sự kiện hook và các quyết định allow, deny, instruct như các chính sách có sẵn.
Ví dụ nhanh
// 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();
},
});
Cài đặt nó:
failproofai policies --install --custom ./my-policies.js
Hai cách để tải các chính sách tùy chỉnh
Tùy chọn 1: Dựa trên quy ước (được khuyến nghị)
Thả các tệp *policies.{js,mjs,ts} vào .failproofai/policies/ và chúng sẽ được tải tự động — không cần các cờ hoặc thay đổi cấu hình. Điều này hoạt động như git hooks: thả một tệp, nó chỉ hoạt động.
# Mức dự án — được cam kết vào git, chia sẻ với nhóm
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs
# Mức người dùng — cá nhân, áp dụng cho tất cả các dự án
~/.failproofai/policies/my-policies.mjs
Cách nó hoạt động:
- Cả hai thư mục dự án và người dùng được quét (hợp nhất — không phải chiến thắng phạm vi đầu tiên)
- Các tệp được tải theo thứ tự bảng chữ cái trong mỗi thư mục. Thêm tiền tố
01-, 02- để kiểm soát thứ tự
- Chỉ các tệp khớp với
*policies.{js,mjs,ts} được tải; các tệp khác bị bỏ qua
- Mỗi tệp được tải độc lập (mở lỗi cho mỗi tệp)
- Hoạt động cùng với các chính sách
--custom rõ ràng và có sẵn
Các chính sách quy ước là cách dễ nhất để xây dựng tiêu chuẩn chất lượng cho tổ chức của bạn. Cam kết .failproofai/policies/ vào git và mỗi thành viên trong nhóm sẽ tự động nhận các quy tắc giống nhau — không cần thiết lập cho mỗi nhà phát triển. Khi nhóm của bạn phát hiện ra các chế độ lỗi mới, hãy thêm một chính sách và đẩy. Theo thời gian, những điều này trở thành một tiêu chuẩn chất lượng sống động tiếp tục cải thiện với mỗi đóng góp.
Tùy chọn 2: Đường dẫn tệp rõ ràng
# Cài đặt với một tệp chính sách tùy chỉnh
failproofai policies --install --custom ./my-policies.js
# Thay thế đường dẫn tệp chính sách
failproofai policies --install --custom ./new-policies.js
# Xóa đường dẫn chính sách tùy chỉnh khỏi cấu hình
failproofai policies --uninstall --custom
Đường dẫn tuyệt đối được giải quyết được lưu trữ trong policies-config.json dưới dạng customPoliciesPath. Tệp được tải mới trên mỗi sự kiện hook - không có bộ nhớ đệm giữa các sự kiện.
Sử dụng cả hai cùng nhau
Các chính sách quy ước và tệp --custom rõ ràng có thể coexist. Thứ tự tải:
- Tệp
customPoliciesPath rõ ràng (nếu được cấu hình)
- Các tệp quy ước dự án (
{cwd}/.failproofai/policies/, theo thứ tự bảng chữ cái)
- Các tệp quy ước người dùng (
~/.failproofai/policies/, theo thứ tự bảng chữ cái)
API
Nhập khẩu
import { customPolicies, allow, deny, instruct } from "failproofai";
customPolicies.add(hook)
Đăng ký một chính sách. Gọi điều này bao nhiêu lần cần thiết cho nhiều chính sách trong cùng một tệp.
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>;
});
Các trợ giúp quyết định
| Hàm | Hiệu ứng | Sử dụng khi |
|---|
allow() | Cho phép hoạt động im lặng | Hành động an toàn, không cần thông báo |
deny(message) | Chặn hoạt động | Agent không nên thực hiện hành động này |
instruct(message) | Thêm ngữ cảnh mà không chặn | Cung cấp cho agent ngữ cảnh bổ sung để duy trì theo dõi |
deny(message) - thông báo xuất hiện trước Claude với tiền tố "Blocked by failproofai:". Một deny duy nhất sẽ ngắn mạch tất cả các đánh giá tiếp theo.
instruct(message) - thông báo được thêm vào ngữ cảnh của Claude cho lệnh gọi công cụ hiện tại. Tất cả các thông báo instruct được tích lũy và được gửi cùng nhau.
Bạn có thể thêm hướng dẫn bổ sung vào bất kỳ thông báo deny hoặc instruct nào bằng cách thêm trường hint trong policyParams — không cần thay đổi mã. Điều này hoạt động cho các chính sách tùy chỉnh (custom/), quy ước dự án (.failproofai-project/), và quy ước người dùng (.failproofai-user/) cũng vậy. Xem Cấu hình → hint để biết chi tiết.
Các thông báo allow có thông tin
allow(message) cho phép hoạt động và gửi lại một thông báo thông tin cho Claude. Thông báo được gửi dưới dạng additionalContext trong phản hồi stdout của trình xử lý hook — cơ chế giống như được sử dụng bởi instruct, nhưng có nghĩa khác: nó là một cập nhật trạng thái, không phải cảnh báo.
| Hàm | Hiệu ứng | Sử dụng khi |
|---|
allow(message) | Cho phép và gửi ngữ cảnh cho Claude | Xác nhận kiểm tra đã vượt qua, hoặc giải thích lý do tại sao kiểm tra bị bỏ qua |
Các trường hợp sử dụng:
- Xác nhận trạng thái:
allow("All CI checks passed.") — cho Claude biết mọi thứ đều tốt
- Giải thích mở lỗi:
allow("GitHub CLI not installed, skipping CI check.") — cho Claude biết lý do tại sao kiểm tra bị bỏ qua để nó có đầy đủ ngữ cảnh
- Nhiều thông báo tích lũy: nếu nhiều chính sách mỗi cái trả về
allow(message), tất cả các thông báo được nối với dòng mới và gửi cùng nhau
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.");
},
});
Các trường PolicyContext
| Trường | Loại | Mô tả |
|---|
eventType | string | "PreToolUse", "PostToolUse", "Notification", "Stop" |
toolName | string | undefined | Công cụ đang được gọi (ví dụ: "Bash", "Write", "Read") |
toolInput | Record<string, unknown> | undefined | Các tham số đầu vào của công cụ |
payload | Record<string, unknown> | Toàn bộ payload sự kiện thô từ Claude Code |
session | SessionMetadata | undefined | Ngữ cảnh phiên (xem bên dưới) |
| Trường | Loại | Mô tả |
|---|
sessionId | string | Mã định danh phiên Claude Code |
cwd | string | Thư mục làm việc của phiên Claude Code |
transcriptPath | string | Đường dẫn đến tệp bản ghi JSONL của phiên |
Các loại sự kiện
| Sự kiện | Khi nó xảy ra | Nội dung toolInput |
|---|
PreToolUse | Trước khi Claude chạy một công cụ | Đầu vào của công cụ (ví dụ: { command: "..." } cho Bash) |
PostToolUse | Sau khi một công cụ hoàn tất | Đầu vào của công cụ + tool_result (đầu ra) |
Notification | Khi Claude gửi thông báo | { message: "...", notification_type: "idle" | "permission_prompt" | ... } - các hook phải luôn trả về allow(), chúng không thể chặn thông báo |
Stop | Khi phiên Claude kết thúc | Trống |
Thứ tự đánh giá
Các chính sách được đánh giá theo thứ tự này:
- Các chính sách có sẵn (theo thứ tự định nghĩa)
- Các chính sách tùy chỉnh rõ ràng từ
customPoliciesPath (theo thứ tự .add())
- Các chính sách quy ước từ dự án
.failproofai/policies/ (tệp theo thứ tự bảng chữ cái, thứ tự .add() bên trong)
- Các chính sách quy ước từ người dùng
~/.failproofai/policies/ (tệp theo thứ tự bảng chữ cái, thứ tự .add() bên trong)
deny đầu tiên sẽ ngắn mạch tất cả các chính sách tiếp theo. Tất cả các thông báo instruct được tích lũy và được gửi cùng nhau.
Nhập bắc cầu
Các tệp chính sách tùy chỉnh có thể nhập các mô-đun cục bộ bằng cách sử dụng các đường dẫn tương đối:
// 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");
},
});
Tất cả các nhập bắc cầu có thể truy cập được từ tệp mục nhập được giải quyết. Điều này được triển khai bằng cách viết lại các nhập from "failproofai" sang đường dẫn dist thực tế và tạo các tệp .mjs tạm thời để đảm bảo tương thích ESM.
Lọc loại sự kiện
Sử dụng match.events để giới hạn khi chính sách xảy ra:
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();
},
});
Bỏ qua match hoàn toàn để xảy ra trên mỗi loại sự kiện.
Xử lý lỗi và các chế độ lỗi
Các chính sách tùy chỉnh mở lỗi: các lỗi không bao giờ chặn các chính sách có sẵn hoặc làm hỏng trình xử lý hook.
| Lỗi | Hành vi |
|---|
customPoliciesPath không được đặt | Không có chính sách tùy chỉnh rõ ràng chạy; các chính sách quy ước và có sẵn tiếp tục bình thường |
| Tệp không tìm thấy | Cảnh báo được ghi vào ~/.failproofai/hook.log; các chính sách có sẵn tiếp tục |
| Lỗi cú pháp/nhập (rõ ràng) | Lỗi được ghi vào ~/.failproofai/hook.log; chính sách tùy chỉnh rõ ràng bị bỏ qua |
| Lỗi cú pháp/nhập (quy ước) | Lỗi được ghi; tệp đó bị bỏ qua, các tệp quy ước khác vẫn tải |
fn ném tại thời gian chạy | Lỗi được ghi; hook đó được coi là allow; các hook khác tiếp tục |
fn mất hơn 10 giây | Hết giờ được ghi; được coi là allow |
| Thư mục quy ước bị thiếu | Không có chính sách quy ước chạy; không có lỗi |
Để gỡ lỗi các lỗi chính sách tùy chỉnh, hãy theo dõi tệp nhật ký:tail -f ~/.failproofai/hook.log
Ví dụ đầy đủ: nhiều chính sách
// 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 };
Ví dụ
Thư mục examples/ chứa các tệp chính sách sẵn sàng để chạy:
| Tệp | Nội dung |
|---|
examples/policies-basic.js | Năm chính sách khởi đầu bao gồm các chế độ lỗi agent phổ biến |
examples/policies-advanced/index.js | Các mô hình nâng cao: nhập bắc cầu, lệnh gọi không đồng bộ, xóa đầu ra, và các hook kết thúc phiên |
examples/convention-policies/security-policies.mjs | Các chính sách bảo mật dựa trên quy ước (chặn ghi .env, ngăn viết lại lịch sử git) |
examples/convention-policies/workflow-policies.mjs | Các chính sách quy trình làm việc dựa trên quy ước (nhắc nhở kiểm tra, tệp ghi kiểm toán) |
Sử dụng các ví dụ tệp rõ ràng
failproofai policies --install --custom ./examples/policies-basic.js
Sử dụng các ví dụ dựa trên quy ước
# 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/
Không cần lệnh cài đặt — các tệp được nhặt lên tự động trên sự kiện hook tiếp theo.