Bỏ qua để đến nội dung

Quản lý mods cho tổ chức

Mod là một plugin chạy code bên trong Claude Code với quyền của user đã cài nó. Mod không chạy trong sandbox. Thông qua managed settings, bạn quyết định mods có được chạy trên máy của user hay không, những mod nào, và theo thứ tự nào. Bạn cũng có thể cài một mod của riêng mình để theo dõi hoặc từ chối những gì các mod khác làm.

Trang này dành cho người triển khai managed settings cho Claude Code, dù dưới dạng file, qua MDM, hay từ admin console của claude.ai. Mods được bật mặc định trong Claude Code v2.1.287 trở lên. Hãy bắt đầu từ phần phù hợp với việc bạn cần làm:

Để không mod nào do user mang vào được nạp, hãy đặt option allowManagedModsOnly trên guard tích hợp sẵn, một policy mod mà Claude Code nạp trước mọi mod do user cài. Option này nằm trong managed settings dưới pluginConfigs, với key là cc-plugin-sec-default@builtin:

managed-settings.json
{
"pluginConfigs": {
"cc-plugin-sec-default@builtin": {
"options": {
"allowManagedModsOnly": true
}
}
}
}

Khi option này được đặt trong managed settings:

  • Không mod nào do user mang vào được nạp: bao gồm mod trong plugin user đã cài, mod nạp bằng --plugin-dir, và mod Claude viết trong một session
  • Mod của tổ chức vẫn được nạp: một mod được tính là của tổ chức không bị kiểm tra. Mọi mod khác được tính là của user và không được nạp. Điều này bao gồm mod trong plugin bạn bật từ một marketplace GitHub hoặc marketplace từ xa khác, và mod mà tổ chức của bạn bật cho các thành viên trên claude.ai. Nếu không có mod nào được tính là của bạn, sẽ không mod đã cài nào được nạp.
  • User không thể hoàn tác: guard chỉ đọc option từ managed settings, nên cùng mục đó đặt trong user, project hay local settings file, hoặc trong một file truyền bằng --settings, đều không thay đổi được gì
  • Policy qua file hoặc MDM áp dụng cho mọi provider: khi bạn phân phối option dưới dạng file hoặc qua MDM, nó hoạt động giống nhau trên Amazon Bedrock, Google Cloud’s Agent Platform và Microsoft Foundry. Với việc phân phối từ admin console của claude.ai, xem Platform availability
  • Các tùy biến khác của user vẫn hoạt động: hook trong settings file, status line và /goal của họ không bị ảnh hưởng
  • Mod tích hợp sẵn vẫn chạy: các mod tích hợp sẵn trong Claude Code, như hỗ trợ AGENTS.md, mỗi cái có công tắc riêng

Để xác nhận option trên máy của một user, khởi động Claude Code ở đó với --plugin-dir và đường dẫn tới một thư mục chứa mod, như claude --plugin-dir ./first-mod. Các hook của mod sẽ không chạy, và transcript cùng debug log có thông báo của guard, ghi tên mod và allowManagedModsOnly. Nếu mod vẫn được nạp, xem Check that a policy is in force và các quy tắc quyết định option có hiệu lực hay không.

Nếu bạn đã đặt CLAUDE_CODE_ENABLE_FUNCTION_HOOKS bằng 0 trong giai đoạn early access, hãy thay nó bằng option này. Claude Code v2.1.287 trở lên bỏ qua biến đó với mọi giá trị, nên giá trị 0 vẫn để mods bật.

Nếu bạn không đặt setting nào cho mods, user của bạn nhận được những điều sau:

  • Mods được bật. User có thể cài plugin chứa mod từ bất kỳ marketplace nào mà plugin settings của bạn cho phép, hoặc nạp mod từ một thư mục bằng --plugin-dir.

  • Một guard tích hợp sẵn chạy đầu tiên. Claude Code nạp một mod tích hợp sẵn tên sec-default@builtin trước mọi mod do user cài. User không tắt được nó. /plugin và debug log liệt kê nó là cc-plugin-sec-default. Guard được nạp khi một trong hai điều sau đúng:

    • Máy có managed settings
    • User đăng nhập Claude Code bằng gói Team hoặc Enterprise

    User xác thực bằng API key, hoặc qua Amazon Bedrock, Google Cloud’s Agent Platform hay Microsoft Foundry, chỉ có guard trên máy có managed settings.

  • Guard bảo vệ những gì bạn quản lý. Mod của user không thể thay đổi những gì managed hooks của bạn nhận hoặc quyết định, system prompt, CLAUDE.md được quản lý và các chỉ dẫn được quản lý khác, những gì bất kỳ mod nào đọc được dưới dạng settings, hoặc các tool và mô tả của managed MCP server.

  • Mọi thứ khác đều được phép. Guard không thêm giới hạn nào khác. Mod của user vẫn có thể đọc và ghi file, khởi chạy process, gửi network request, viết lại tool call và prompt, từ chối một tool call, duyệt một call lẽ ra phải hỏi, và vẽ giao diện, tất cả với quyền của user đó.

  • Deny rule và managed hooks của bạn được ưu tiên. Ở nơi guard được nạp, mod của user không thể duyệt một call mà rule deny từ chối, bất kể rule nằm trong settings file nào. Một quyết định chặn từ PreToolUse hook trong managed settings cũng là cuối cùng. Cả hai áp dụng cho tool call của Claude. Không cái nào áp dụng cho các lời gọi $.fs và $.process của chính mod: với Read(.env) bị deny, mod vẫn đọc được file đó bằng $.fs.read hoặc khởi chạy một chương trình đọc nó. Để giới hạn các lời gọi đó, hãy ngăn mod được nạp hoặc xử lý lời gọi trong một policy mod.

  • Các kiểm tra permission khác có thể bị vượt qua. Mod của user có khả năng duyệt tool call có thể duyệt một call mà rule ask lẽ ra phải hỏi, hoặc call đã bị một PreToolUse hook ngoài managed settings chặn. Ở auto mode, một call mà mod duyệt sẽ chạy mà không qua bước kiểm tra của classifier.

Mã nguồn của guard được công khai trong thư mục mods/sec-default của repository Claude Code.

Mods không thay thế các kiểm soát bạn đang có:

  • Settings hooks vẫn hoạt động. Các hook dạng command, HTTP, prompt và agent trong settings file và trong hooks/hooks.json của plugin vẫn chạy như trước, song song với mods. Không có gì trong số đó bị deprecated.
  • Deny rule được ưu tiên ở nơi guard được nạp. Mod của user không thể duyệt một call mà rule deny từ chối, trừ khi bạn đặt allowModsToOverrideDenyRules.
  • Managed hooks chạy đầu tiên. Một PreToolUse hook trong managed settings chạy trước khi bất kỳ mod nào thấy tool call, và quyết định chặn của nó là cuối cùng. Nếu sau đó một mod viết lại call, managed hooks của bạn chạy lại trên call đã được viết lại, nên quyết định chặn vẫn áp dụng. PreToolUse hook từ các settings file khác và từ plugin chạy sau mod cuối cùng, nên một mod trả về kết quả riêng thay vì chạy tool sẽ khiến các hook đó không chạy. Xem Thứ tự chạy của các mod.
  • Network policy bao gồm $.http.fetch. Nếu tổ chức của bạn tắt web fetching, hoặc lưu lượng mạng không thiết yếu bị tắt cho session, Claude Code sẽ từ chối network request mà mod gửi bằng $.http.fetch. Policy không bao gồm chương trình mà mod khởi chạy bằng $.process.run. Chương trình đó truy cập mạng bằng quyền của chính user.
  • Kiểm soát plugin áp dụng cho mods. Mod là một plugin, nên các setting giới hạn những gì user được cài, như strictKnownMarketplaces, quyết định nó có được cài hay không.
  • Mod không thay đổi được permission prompt. Mod có thể đổi style phần lớn giao diện Claude Code, nhưng không đụng được vào permission prompt, nên không thể thay đổi những gì prompt hiển thị. Mod vẫn có thể duyệt hoặc từ chối một tool call trước khi prompt xuất hiện, như phần Mặc định sẽ như thế nào mô tả.
  • Trust prompt đi trước. Trong một session tương tác ở thư mục user chưa tin cậy, không mod nào được nạp cho đến khi họ trả lời trust prompt.
  • --safe-mode tắt các mod đã cài, kể cả mod của bạn. Khởi động session bằng claude --safe-mode để kiểm tra xem một mod có gây ra sự cố hay không.

Không kiểm soát nào trong số này đưa mod vào sandbox. Một mod được bạn cho phép sẽ chạy với tư cách user, với quyền truy cập file, process và mạng của user.

Mod làm được nhiều hơn các phần khác của plugin vì nó chạy bên trong Claude Code. Nó thấy mọi prompt và tool call, có thể thay đổi chúng, và có thể cho phép hoặc từ chối một tool call trước khi permission prompt xuất hiện.

Những gì user có thể nạp dưới dạng mod phụ thuộc vào các kiểm soát plugin bạn đang có:

Kiểm soát plugin hiện tại của bạnUser có thể nạp mod từ đâu
Không cóMod từ bất kỳ marketplace nào, từ bất kỳ thư mục nào bằng --plugin-dir, hoặc do Claude viết trong một session
Một allowlist marketplaceMod từ các marketplace bạn cho phép, hoặc từ bất kỳ thư mục nào bằng --plugin-dir. Mod do Claude viết trong một session chỉ được nạp khi allowlist có skills-dir.
Một allowlist marketplace và disableSideloadFlagsMod từ các marketplace bạn cho phép

Trang Manage plugins for your organization liệt kê các cách một plugin được nạp và setting kiểm soát từng cách.

Để kiểm tra các mod trong một marketplace trước khi user cài, xem Xem xét những gì mod có thể làm. Để chặn mod của user cho đến khi bạn làm xong việc đó, xem Chặn mod do user cài.

Bạn có thể xem một mod làm được gì mà không cần chạy nó. Trong shell, chạy claude plugin validate trên thư mục của plugin:

Terminal window
claude plugin validate ./some-mod

Hai dòng trong output mô tả code của mod:

❯ ./register.js hooks: session.start, tool.call, ui.render{component=Pane}
❯ ./register.js calls: $.fs.read, $.http.fetch, $.store.set, $.ui.open

Dòng hooks: liệt kê các event mà mod nhận. Dòng calls: liệt kê các method của mods API mà code của nó gọi. Mods API, viết là $ trong code của mod, là cách mod truy cập file, process và mạng. Claude Code từ chối nạp một mod dùng mods API theo cách mà lệnh này không đọc được.

Hãy để ý các lời gọi sau trong dòng calls::

Lời gọiÝ nghĩa
$.fs.read, $.fs.writeĐọc hoặc ghi file ở bất cứ đâu user có quyền
$.process.run, $.process.spawnKhởi chạy chương trình với tư cách user
$.http.fetchGửi network request
$.env.get, $.settings.readĐọc biến môi trường và settings, có thể chứa API key. Một dòng env reads: trong output ghi tên từng biến.
$.env.setĐặt một biến môi trường cho Claude Code và cho mọi lệnh và MCP server nó khởi chạy sau đó, có thể thay đổi những gì các chương trình đó chạy. Một dòng env writes: ghi tên từng biến.
$.mcp.callGọi một tool trên MCP server đang kết nối, theo các permission rule của session
$.model.completeDùng gói hoặc API key của user để gọi model
$.prompt.submitGửi một prompt, và có thể gửi như lời của chính user
$.session.sendGửi một tin nhắn mà Claude của session khác hoặc subagent khác sẽ đọc

Trong dòng hooks:, tool.call và prompt.submit nghĩa là mod thấy mọi tool call và mọi prompt, và có thể thay đổi chúng. session.append nghĩa là mod có thể viết lại từng dòng của cuộc hội thoại trước khi nó được lưu. ui.render{component=AskUserQuestion} nghĩa là mod có thể vẽ lại hộp thoại Claude dùng để hỏi user. tool.check nghĩa là mod có thể duyệt hoặc từ chối một tool call trước khi permission prompt xuất hiện. Phần Mặc định sẽ như thế nào liệt kê những rule và hook nào của bạn được ưu tiên hơn câu trả lời của nó.

Các policy cho mods trải từ không cho phép mod đã cài nào đến cho phép bất kỳ mod nào user chọn, với mod của riêng bạn kiểm tra các mod khác, và mỗi policy chỉ là vài managed setting. Tìm policy bạn muốn ở cột đầu và đặt những gì cột thứ hai ghi. Trang Deploy managed settings mô tả managed settings nằm ở đâu.

Bạn muốnSettings
Không mod đã cài nào, hooks giữ nguyênĐặt allowManagedModsOnly và không triển khai mod nào của riêng bạn
Không mod đã cài nào và không hook nào cả, kể cả managed hooks của bạnĐặt disableAllHooks là true
Chỉ mod của tổ chứcĐặt option allowManagedModsOnly của guard, và cài mod của bạn sao cho chúng được tính là của bạn
Bất kỳ mod nào từ các marketplace bạn duyệtGiữ giới hạn marketplace, và đặt disableSideloadFlags là true
Bất kỳ mod nào, với mod của riêng bạn kiểm tra các mod khácCài mod của bạn, và liệt kê nó cùng sec-default@builtin trong prependPlugins

Mỗi setting có tác dụng như sau:

  • allowManagedModsOnly: một option của guard tích hợp sẵn. Mod của user không được nạp, còn settings hooks, status line và /goal của họ vẫn hoạt động. Phần Chặn mod do user cài liệt kê phạm vi của nó.
  • allowManagedHooksOnly: một setting rộng hơn. Chỉ mod của tổ chức và mod tích hợp sẵn trong Claude Code được nạp. Mod do user tự cài thì không. Setting này cũng chặn hook trong settings file của user. Hãy đọc What runs under allowManagedHooksOnly trước khi đặt nó.
  • disableAllHooks: setting rộng nhất. Trong managed settings, nó dừng mod trong mọi plugin đã cài, kể cả của bạn, và tắt mọi hook trong settings file, nên một PreToolUse hook trong managed settings của bạn không còn chặn được gì. Status line tùy chỉnh và /goal cũng ngừng hoạt động. Hãy đọc disableAllHooks trước khi đặt nó.
  • disableSideloadFlags: từ chối --plugin-dir và --plugin-url lúc khởi động, và ngăn mod do Claude viết trong session được nạp. Setting này cũng từ chối --agents và --mcp-config. Hãy đọc disableSideloadFlags trước khi đặt nó.

Các mod tích hợp sẵn trong Claude Code, như hỗ trợ AGENTS.md, không bị các setting này ảnh hưởng. Mỗi cái có công tắc riêng.

User có mod không được nạp sẽ tìm thấy lý do trong debug log của họ. Phần Thông báo từ chối liệt kê các dòng cho allowManagedHooksOnly và disableAllHooks, còn phần Thông báo từ guard tích hợp sẵn có dòng cho allowManagedModsOnly.

Để chạy mod của tổ chức và chặn mod do user mang vào, hãy triển khai các setting ở dòng Chỉ mod của tổ chức trong bảng policy, cộng thêm disableSideloadFlags. Với file managed-settings.json hoàn chỉnh dưới đây, Claude Code từ chối mod của user, nên không hook nào của chúng chạy, và policy mod của bạn chạy trước các mod khác:

managed-settings.json
{
"extraKnownMarketplaces": {
"acme-tools": {
"source": { "source": "directory", "path": "/opt/acme/claude-plugins" }
}
},
"enabledPlugins": { "acme-guard@acme-tools": true },
"prependPlugins": ["acme-guard@acme-tools", "sec-default@builtin"],
"pluginConfigs": {
"cc-plugin-sec-default@builtin": {
"options": { "allowManagedModsOnly": true }
}
},
"disableSideloadFlags": true
}

Mỗi nhóm key làm một việc:

  • extraKnownMarketplaces, enabledPlugins và prependPlugins: cài mod của bạn sao cho nó được tính là của bạn, và cho nó chạy đầu tiên với guard ngay sau. Phần Cài mod của tổ chức và sắp xếp thứ tự mô tả thư mục mà các key này trỏ tới.
  • pluginConfigs: đặt option allowManagedModsOnly của guard, để Claude Code từ chối mod của user. Settings hooks, status line và /goal của họ vẫn hoạt động.
  • disableSideloadFlags: xem disableSideloadFlags để biết các cờ nó từ chối lúc khởi động

Để xác nhận policy trên một máy thử nghiệm, trong shell, khởi động session bằng claude --debug và đọc debug log:

  • Mod của bạn: dòng hooks module của nó có tier prepend
  • Một mod user đã cài: có một dòng refused by cc-plugin-sec-default: mods are limited to your organization's by policy (allowManagedModsOnly). Một dòng trước đó nói hooks module của mod đó đã loaded, nên hãy tìm dòng từ chối.
  • Một thư mục plugin: claude --plugin-dir ./any-mod thoát với thông báo bắt đầu bằng --plugin-dir is disabled by your organization's managed settings (disableSideloadFlags)

Để giới hạn thêm những marketplace mà user được thêm, kết hợp file này với giới hạn marketplace của bạn.

Mod là một plugin, nên các cách bạn quản lý plugin cho tổ chức cũng áp dụng cho plugin chứa mod:

Guard tích hợp sẵn nhận các option. Đặt chúng trong managed settings dưới pluginConfigs, với key là cc-plugin-sec-default@builtin, như ví dụ ở phần Chặn mod do user cài.

Bảng dưới cho biết user nhận được gì khi mỗi option không được đặt và khi được đặt là true:

OptionKhông đặttrue
allowManagedModsOnlyMod của user được nạpChỉ mod của tổ chức, và mod tích hợp sẵn trong Claude Code, được nạp. Claude Code từ chối mọi mod khác, kể cả mod user đã cài hoặc chỉ định bằng --plugin-dir.
allowModsToOverrideDenyRulesDeny rule được ưu tiên hơn mod của userMod của user có khả năng duyệt tool call có thể duyệt một call mà rule deny từ chối

Các quy tắc sau quyết định một option có hiệu lực hay không:

  • id chỉ có một dạng ở đây: Claude Code chỉ đọc option dưới cc-plugin-sec-default@builtin. prependPlugins chấp nhận cả sec-default@builtin, còn pluginConfigs thì không.
  • Chỉ managed settings mới có tác dụng: cùng mục đó đặt trong user, project hay local settings file, hoặc trong một file truyền bằng --settings, không đặt được option cũng không nới lỏng được option
  • Guard phải được nạp: nếu bạn đặt prependPlugins, hãy ghi tên guard trong danh sách. Ở nơi guard không được nạp, không option nào áp dụng.
  • Guard “đóng khi lỗi” (fail closed): nếu guard không đọc được managed settings, nó từ chối mọi mod của user lúc nạp. Nếu nó không kiểm tra được các deny rule cho một call mà mod của user đã duyệt, nó từ chối call đó.

Các thông báo từ guard tích hợp sẵn là những gì user của bạn thấy khi một trong hai option có hiệu lực.

Bạn có thể triển khai mod của riêng mình cho mọi user, chọn vị trí chạy của chúng so với mod của user, và dùng một mod để thực thi policy.

Cài mod của tổ chức và sắp xếp thứ tự

Phần tiêu đề “Cài mod của tổ chức và sắp xếp thứ tự”

Mod của tổ chức được nạp ở những nơi mod của user không được nạp và có thể chạy trước chúng, nên Claude Code phải phân biệt được mod nào đến từ bạn. Nó chỉ coi một mod là của tổ chức khi tất cả các điều sau đều đúng:

  • Managed enabledPlugins đặt plugin của mod là true
  • Managed settings chỉ định marketplace của plugin là một thư mục trên máy của user, bằng đường dẫn tuyệt đối. Một mục extraKnownMarketplaces làm được việc đó và đồng thời đăng ký marketplace cho user.
  • Marketplace liệt kê plugin bằng đường dẫn tương đối, để Claude Code nạp nó tại chỗ từ thư mục đó

Để đáp ứng các điều kiện này, hãy cho hệ thống quản lý thiết bị (device management) copy thư mục marketplace vào cùng một đường dẫn trên mọi máy. Cho thư mục đó và mọi thư mục cha của nó chỉ administrator mới ghi được, giống như file managed settings. Bất kỳ ai ghi được vào đó đều có thể viết lại mod của bạn. Managed settings phân phối từ admin console của claude.ai có thể mang các key này, nhưng không đặt được thư mục lên máy.

Thư mục chứa manifest của marketplace và plugin:

/opt/acme/claude-plugins/
├── .claude-plugin/
│ └── marketplace.json
└── plugins/
└── acme-guard/
├── .claude-plugin/
│ └── plugin.json
└── hooks/
├── hooks.json
└── register.js

Manifest liệt kê plugin bằng đường dẫn tương đối so với thư mục đó:

/opt/acme/claude-plugins/.claude-plugin/marketplace.json
{
"name": "acme-tools",
"owner": { "name": "Acme" },
"plugins": [
{ "name": "acme-guard", "source": "./plugins/acme-guard", "description": "Acme policy mod" }
]
}

Một plugin mà Claude Code copy vào cache của nó được tính là của user, kể cả khi managed enabledPlugins bật nó. Điều này bao gồm mọi plugin từ nguồn GitHub, git, URL hoặc npm. Mod của nó chạy cùng các mod của user, prependPlugins và appendPlugins bỏ qua nó, và nó không được nạp khi có allowManagedModsOnly hay allowManagedHooksOnly. Debug log của user có một dòng bắt đầu bằng id của plugin và is enabled by managed settings, but.

Claude Code kích hoạt một event mỗi khi nó sắp hành động, như chạy một tool, và chuyển event đó lần lượt qua từng mod. Một mod được tính là của bạn chạy trước mod của user kể cả khi bạn không liệt kê nó ở đâu. Để đặt vị trí của nó, hãy ghi id của nó vào một trong hai setting. id là tên plugin, @, rồi tên marketplace, như acme-guard@acme-tools.

  • prependPlugins: mod của bạn thấy mọi event trước mọi mod của user và thấy mọi kết quả sau chúng. Nó có thể thay đổi event, từ chối event, hoặc bỏ qua các mod của user.
  • appendPlugins: mod của bạn chạy sau mọi mod của user, nên nó chỉ thấy những event mà các mod đó chuyển tiếp, ở dạng chúng chuyển tiếp

Ví dụ này khai báo marketplace acme-tools tại /opt/acme/claude-plugins, bật acme-guard từ đó, và cho mod đó chạy đầu tiên, với guard tích hợp sẵn ngay sau:

managed-settings.json
{
"extraKnownMarketplaces": {
"acme-tools": {
"source": { "source": "directory", "path": "/opt/acme/claude-plugins" }
}
},
"enabledPlugins": { "acme-guard@acme-tools": true },
"prependPlugins": ["acme-guard@acme-tools", "sec-default@builtin"]
}

Mỗi key làm một việc:

  • extraKnownMarketplaces: chỉ định thư mục chứa marketplace acme-tools. path là đường dẫn tuyệt đối của thư mục chứa .claude-plugin/marketplace.json.
  • enabledPlugins: bật acme-guard cho mọi user nhận được các managed settings này
  • prependPlugins: đặt acme-guard đầu tiên và guard tích hợp sẵn thứ hai, cả hai đều trước mọi mod do user cài. Claude Code tuân theo thứ tự bạn liệt kê.

Để xác nhận máy của user đã nhận được settings, xem Check that a policy is in force.

Để xác nhận vị trí chạy của mod, khởi động một session trên máy đó bằng claude --debug và tìm id của mod trong debug log:

  • hooks module acme-guard@acme-tools loaded, kèm tier prepend: mod được tính là của tổ chức và chạy đầu tiên
  • Cùng dòng đó nhưng kèm tier user: Claude Code coi nó là mod của user. Một dòng thứ hai, prependPlugins names acme-guard@acme-tools, which is not an enabled managed plugin with a hooks module; skipped, cho biết danh sách đã bỏ qua nó.

Các quy tắc sau quyết định những id nào trong hai danh sách có hiệu lực:

  • Danh sách thay thế giá trị mặc định: khi bạn đặt prependPlugins trong managed settings, hãy ghi sec-default@builtin vào đó để giữ guard tích hợp sẵn. Guard là tích hợp sẵn nên không cần mục enabledPlugins.
  • id của bạn phải được tính là của bạn: trong managed settings, Claude Code bỏ qua id nào có plugin không đáp ứng các điều kiện để là mod của tổ chức
  • Repository không đặt được chúng: Claude Code đọc cả hai setting từ managed settings và không bao giờ đọc từ settings file của repository. User có thể đặt chúng trong ~/.claude/settings.json để sắp xếp mod của chính họ, nhưng chỉ trên máy không có managed settings, và chỉ khi họ không đăng nhập bằng gói Team hoặc Enterprise. Ở mọi nơi khác, Claude Code bỏ qua cả hai key trong user settings. Một danh sách ở đó không thêm cũng không bớt được guard tích hợp sẵn.

Để chặn mọi mod của user, bạn không cần mod riêng. Hãy đặt allowManagedModsOnly. Hãy viết một policy mod khi bạn muốn cho phép một số mod của user và từ chối số khác, hoặc để ghi lại những gì các mod làm.

Mỗi khi một mod khác sắp được nạp, mod của bạn nhận được danh sách mà claude plugin validate in ra, trong một event tên là plugin.register. Một mod trong prependPlugins có thể đọc danh sách đó và từ chối mod. Nó cũng có thể xử lý bất kỳ lời gọi mods API nào theo tên để ghi lại hoặc từ chối lời gọi đó với mọi mod khác. Tên là method bỏ $., nên một hook trên fs.write thấy mọi lời gọi $.fs.write.

Policy mod dưới đây từ chối mọi mod của user có code gọi $.process.run hoặc $.process.spawn. Nó cũng ghi audit log, ghi mỗi tool call và mỗi file mà một mod ghi vào debug log. Vì nó chạy đầu tiên, log ghi lại những gì đã được yêu cầu, trước khi bất kỳ mod nào của user thay đổi nó. Lưu thành acme-guard/hooks/register.js:

acme-guard/hooks/register.js
// Các method mà không mod nào của user được gọi, mỗi cái viết dạng namespace.method
const BLOCKED_CALLS = ['process.run', 'process.spawn']
export function register(on) {
// Chạy mỗi khi một mod khác sắp được nạp
on('plugin.register', async ($, e, next) => {
// Giữ lại các lời gọi trong code của mod đó nằm trong danh sách bị chặn
const blocked = e.uses.calls.filter((call) => BLOCKED_CALLS.includes(call))
if (e.tier === 'user' && blocked.length > 0) {
// Trả về refuse sẽ ngăn mod được nạp, và đoạn text là lý do
return { refuse: 'Acme policy: mods may not call ' + blocked.join(', ') }
}
// Cho mọi mod khác được nạp
return next(e)
})
// Ghi lại mỗi tool call, rồi cho nó đi tiếp nguyên vẹn
on('tool.call', async ($, e, next) => {
$.ui.log('audit tool.call ' + e.tool, { to: 'debug' })
return next(e)
})
// Ghi lại mod nào đã ghi file, rồi đường dẫn, đặt trong ngoặc kép vì do mod chọn
on('fs.write', async ($, e, next) => {
$.ui.log('audit fs.write by ' + next.origin.plugin + ' ' + JSON.stringify(e.path), { to: 'debug' })
return next(e)
})
}

File đăng ký ba hook:

  • plugin.register: quyết định một mod khác có được nạp hay không. Nó từ chối mod của user có gọi method bị chặn và cho mọi mod khác đi tiếp.
  • tool.call: ghi một dòng như audit tool.call Bash vào debug log cho mỗi tool call, và không thay đổi gì
  • fs.write: ghi một dòng như audit fs.write by reader "/tmp/notes.md" cho mỗi lời gọi $.fs.write mà mod khác thực hiện, và không thay đổi gì. Tên mod đứng trước và đường dẫn được đặt trong ngoặc kép, để một đường dẫn do mod chọn không thể giả làm một field khác của dòng log.

Hook plugin.register đọc hai field của event:

  • e.tier: vị trí mà mod sẽ chạy, là một trong prepend, user, append hoặc builtin. Mọi mod do một người cài đều là user.
  • e.uses.calls: các method của mods API mà mod gọi, mỗi cái viết dạng namespace.method như process.run, không có $. như claude plugin validate in ra

Khi user cài một mod gọi $.process.run, mod đó không được nạp, và debug log của họ có một dòng kết thúc bằng refused by acme-guard: kèm lý do của bạn. Thông báo từ chối cũng xuất hiện trong transcript ở một session hot-reload thư mục plugin. Để chặn một lời gọi mà không từ chối cả mod, hãy trả về { deny: 'your reason' } từ một hook trên tên của lời gọi đó.

Để gửi các dòng audit tới nơi khác ngoài debug log, gọi $.http.fetch từ chính các hook đó.

Một session có thể chạy mà không có mod của bạn. Nếu worker thread chạy các mod đã cài crash ba lần, Claude Code gỡ mọi mod không phải tích hợp sẵn, kể cả mod của bạn, cho đến khi user chạy /reload-plugins hoặc bắt đầu session mới. Và user khởi động Claude Code với --safe-mode sẽ chạy mà không có mod đã cài nào, kể cả mod của bạn.

Trang Tạo một mod mô tả các file mà một mod cần. Phần Kiểm thử policy mod có một file test cho policy mod này.

Nếu hook plugin.register của bạn ném lỗi hoặc vượt giới hạn thời gian, Claude Code bỏ qua hook đó, nên việc kiểm tra “mở khi lỗi” (fail open) và mod đang được kiểm tra sẽ được nạp. Để “đóng khi lỗi” và từ chối mod của user, hãy chuyển phần kiểm tra vào một hàm có tên và thêm một .catch handler trả về lời từ chối. Phiên bản file này chỉ hiển thị hook plugin.register, nên hãy giữ hai hook audit từ phiên bản đầu trong register:

acme-guard/hooks/register.js
const BLOCKED_CALLS = ['process.run', 'process.spawn']
// Cùng phần kiểm tra như trước, chuyển vào một hàm riêng
async function checkMod($, e, next) {
const blocked = e.uses.calls.filter((call) => BLOCKED_CALLS.includes(call))
if (e.tier === 'user' && blocked.length > 0) {
return { refuse: 'Acme policy: mods may not call ' + blocked.join(', ') }
}
return next(e)
}
export function register(on) {
// Handler chỉ chạy khi checkMod ném lỗi hoặc vượt giới hạn thời gian
on('plugin.register', checkMod).catch(async ($, e, next) => {
// Cho mod của tổ chức và mod tích hợp sẵn được nạp
if (e.tier !== 'user') return next(e)
// Từ chối mod của user không kiểm tra được
return { refuse: 'Acme policy check failed, so this mod was not loaded' }
})
}

Với handler này, một mod đang được kiểm tra khi phần kiểm tra ném lỗi hoặc hết thời gian sẽ không được nạp, và dòng từ chối mang lý do thứ hai, như refused by acme-guard: Acme policy check failed, so this mod was not loaded. Handler chuyển mọi mod ngoài tier user tới next(e), nên một lần kiểm tra thất bại không chặn các mod mà tổ chức của bạn liệt kê. Phần Xử lý hook bị lỗi mô tả .catch cho các event khác.

Bài tiếp theo: Tùy biến Claude Code bằng mods - Bài viết giới thiệu mods từ blog của Claude: vì sao Anthropic xây dựng mods và mods dành cho team, doanh nghiệp.