
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@cuzfrog/module-gates
Advanced tools
Controls the entropy of the codebase by enforcing code module boundaries. Ships bridges for pi, Claude Code, and Devin CLI.
Hooks that controls the entropy of the codebase by enforcing module boundaries, helping combat slops.
Supported agent harnesses:
Adding support for another agent (qwen-code, cursor, ...) means adding a bridge.
Module contracts as guardrails. Each directory can contain a descriptor file (default MODULE.md) that declares:
readonly — files cannot be editedno-new-exports — files where no new exports are allowed (body still editable)The extension intercepts agent write/edit operations and enforces these contracts. Violations are blocked with a reason.
The attempt to add 2 public helper functions is blocked, forcing the agent to re-think the design.

no-new-exports list?index.ts or mod.rs. A child module may import from a parent module's internal files (not recommended but allowed). (Only Typescript/JavaScript and Rust are supported)pi install npm:@cuzfrog/module-gates
Or load directly for a single session:
pi -e npm:@cuzfrog/module-gates
As a plugin, from this repository's marketplace (no login required — public repo):
/plugin marketplace add cuzfrog/module-gates
/plugin install module-gates@cuzfrog
On the first hook invocation the plugin installs its runtime dependencies into its data directory.
Or as plain hooks wired into a project (requires the package installed in the project):
npm install --save-dev @cuzfrog/module-gates
npx module-gates install-claude
This writes PreToolUse and SessionStart hooks into .claude/settings.json; npx module-gates uninstall-claude removes them. The SessionStart hook injects the system prompt hint automatically.
Or reuse an existing pi installation by pointing hooks at it manually in ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "node \"$HOME/.pi/agent/npm/node_modules/@cuzfrog/module-gates/src/bridges/claude/run.mjs\" pre-tool-use"
}
]
}
],
"SessionStart": [
{
"matcher": "startup|resume|clear",
"hooks": [
{
"type": "command",
"command": "node \"$HOME/.pi/agent/npm/node_modules/@cuzfrog/module-gates/src/bridges/claude/run.mjs\" session-start"
}
]
}
]
}
}
The pi install directory may differ; locate run.mjs under your pi npm root. The SessionStart hook (system prompt injection) is optional — PreToolUse alone enforces the gates.
As a plugin (requires the package installed in the project):
npm install --save-dev @cuzfrog/module-gates
devin plugins install cuzfrog/module-gates
Or as plain hooks wired into a project:
npm install --save-dev @cuzfrog/module-gates
npx module-gates install-devin
This writes PreToolUse and SessionStart hooks into .devin/hooks.v1.json; npx module-gates uninstall-devin removes them. The SessionStart hook injects the system prompt hint automatically. When a gate violation is detected, the PreToolUse hook rejects the tool call and reports the reason to the agent.
Or point at the package manually in .devin/hooks.v1.json:
{
"PreToolUse": [
{
"matcher": "^(write|edit|apply_patch)$",
"hooks": [
{
"type": "command",
"command": "node \"${DEVIN_PROJECT_DIR}/node_modules/@cuzfrog/module-gates/src/bridges/devin/run.mjs\" pre-tool-use"
}
]
}
],
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "node \"${DEVIN_PROJECT_DIR}/node_modules/@cuzfrog/module-gates/src/bridges/devin/run.mjs\" session-start"
}
]
}
]
}
For a global or custom install, replace ${DEVIN_PROJECT_DIR}/node_modules with the path where the package lives (e.g. $(npm root -g)). The SessionStart hook (system prompt injection) is optional — the PreToolUse hook enforces the gates.
A module descriptor is a Markdown file (default name: MODULE.md) placed in a directory. You can piggy-back on your module context file for example CONTEXT.md. A MODULE.md only enforces its own immediate directory.
---
readonly: [mod.rs]
---
Any prose for the agent to better understand the module.
no-new-exports: [mod.rs]
No-new-exports files cannot change their surface size: no new exports or public entries are allowed. The file body is still editable.
A skill module-no-new-exports-all has been included to populate no-new-exports entries in modules.
| Scenario | Behavior |
|---|---|
No MODULE.md | Module is unconstrained — nothing is gated. |
| Malformed YAML frontmatter | The module is left unguarded and an info notification is emitted. |
The canonical agent-independent location is .module-gates/config.json (the whole file is the config, no wrapper key). When it is absent, each bridge falls back to the agents' settings files under a module-gates key — e.g. .pi/settings.json, .claude/settings.json.
{
"module-gates": {
"moduleDescriptorFileName": "MODULE.md",
"moduleDescriptorReadonly": "off",
"sourceRoots": ["src/"],
"outputModuleProseOnBlock": false
}
}
| Option | Default | Description |
|---|---|---|
moduleDescriptorFileName | MODULE.md | File name used for module descriptors (case-insensitive) |
moduleDescriptorReadonly | "off" | "file" makes the whole descriptor readonly; "frontmatter" locks only the YAML frontmatter (body prose stays editable); "off" disables descriptor readonly. true/false are also accepted for backward compatibility. |
sourceRoots | ["src/"] | Directories where gates are enforced. Descriptor files are discovered across the whole project regardless of this setting. Pass a single string for one root, or an array for multiple roots (e.g. monorepos with ["packages/app/src/", "packages/lib/src/"]). Use [""] to enforce from the project root. Legacy singular sourceRoot (string) is still accepted. |
disableModuleInterfaceImportGate | false | When true, imports will not be forced to be from module interface. |
disableSystemPrompt | false | When true, skip injecting the module-gates hint into the agent's system prompt. |
outputModuleProseOnBlock | false | When true, the violating module descriptor's prose is appended to the block message so the agent sees the contract context. Disabled by default to keep the error message concise. |
When no settings file exists or no module-gates key is present, defaults apply.
Prompt:
Check if PreToolUse hook `module-gates` is triggered and runs expectedly.
MIT
Cause Chung (cuzfrog@gmail.com)
FAQs
Controls the entropy of the codebase by enforcing code module boundaries. Ships bridges for pi, Claude Code, and Devin CLI.
We found that @cuzfrog/module-gates demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.