Nous.Permissions (nous v0.16.5)
View SourceTool-level permission policy engine.
Controls which tools can be used, which require user approval,
and which are denied entirely. This operates at the tool level —
for message-level input filtering, see Nous.Plugins.InputGuard.
Quick Start
# Use a preset policy
policy = Nous.Permissions.default_policy()
# Check tool access
Nous.Permissions.blocked?(policy, "bash")
#=> false
Nous.Permissions.requires_approval?(policy, "bash")
#=> true
Nous.Permissions.requires_approval?(policy, "file_read")
#=> false
# Filter a tool list
tools = [bash_tool, read_tool, write_tool]
allowed = Nous.Permissions.filter_tools(policy, tools)Custom Policies
policy = %Nous.Permissions.Policy{
mode: :default,
deny_names: MapSet.new(["bash"]),
deny_prefixes: ["web_"],
approval_required: MapSet.new(["file_write", "file_edit"])
}
Summary
Functions
Checks if a tool name is blocked by the policy.
Creates a policy from keyword options.
Returns the default permission policy.
Filters a list of Nous.Tool structs, removing blocked tools.
Partitions tools into {allowed, blocked} based on the policy.
Returns a permissive policy where all tools are open.
Checks if a tool requires approval under the policy.
Checks if a tool requires approval, accounting for its category.
Returns a strict policy where all tools require approval.
Functions
@spec blocked?(Nous.Permissions.Policy.t(), String.t()) :: boolean()
Checks if a tool name is blocked by the policy.
Matches against deny_names (exact, case-insensitive) and deny_prefixes (prefix match, case-insensitive).
Examples
iex> policy = %Nous.Permissions.Policy{deny_names: MapSet.new(["bash"]), deny_prefixes: ["web_"]}
iex> Nous.Permissions.blocked?(policy, "bash")
true
iex> Nous.Permissions.blocked?(policy, "web_fetch")
true
iex> Nous.Permissions.blocked?(policy, "file_read")
false
@spec build_policy(keyword()) :: Nous.Permissions.Policy.t()
Creates a policy from keyword options.
Options
:mode—:default,:permissive, or:strict:deny— list of tool names to block:deny_prefixes— list of prefixes to block (e.g.["web_"]):approval_required— list of tool names requiring approval:allow_unattended_execute— whentrue,:permissivemode also drops the approval gate forcategory: :executetools (e.g.bash). Defaults tofalse: even under:permissive, execute-class tools still require approval so one config choice can't turn an LLM into unattended RCE.
Examples
policy = Nous.Permissions.build_policy(
mode: :default,
deny: ["bash"],
deny_prefixes: ["web_"],
approval_required: ["file_write"]
)
@spec default_policy() :: Nous.Permissions.Policy.t()
Returns the default permission policy.
Read and search tools are open. Write and execute tools require approval.
@spec filter_tools(Nous.Permissions.Policy.t(), [Nous.Tool.t()]) :: [Nous.Tool.t()]
Filters a list of Nous.Tool structs, removing blocked tools.
Examples
tools = [bash_tool, read_tool, write_tool]
policy = Nous.Permissions.build_policy(deny: ["bash"])
filtered = Nous.Permissions.filter_tools(policy, tools)
# Returns [read_tool, write_tool]
@spec partition_tools(Nous.Permissions.Policy.t(), [Nous.Tool.t()]) :: {[Nous.Tool.t()], [Nous.Tool.t()]}
Partitions tools into {allowed, blocked} based on the policy.
Examples
{allowed, denied} = Nous.Permissions.partition_tools(policy, tools)
@spec permissive_policy() :: Nous.Permissions.Policy.t()
Returns a permissive policy where all tools are open.
@spec requires_approval?(Nous.Permissions.Policy.t(), String.t()) :: boolean()
Checks if a tool requires approval under the policy.
Examples
iex> policy = Nous.Permissions.strict_policy()
iex> Nous.Permissions.requires_approval?(policy, "file_read")
true
iex> policy = Nous.Permissions.permissive_policy()
iex> Nous.Permissions.requires_approval?(policy, "bash")
false
@spec requires_approval?(Nous.Permissions.Policy.t(), String.t(), atom() | nil) :: boolean()
Checks if a tool requires approval, accounting for its category.
Identical to requires_approval?/2 except that category: :execute tools
(e.g. bash) are NOT auto-approved under :permissive mode unless the policy
sets allow_unattended_execute: true. This keeps the single :permissive
switch from silently turning an LLM into unattended remote-code-execution: the
per-tool requires_approval flag and the policy already compose, but a custom
execute-class tool that relies on the policy for its gate would otherwise be
unguarded under :permissive.
category is the tool's declared Nous.Tool category (:execute, :write,
:read, …) or nil.
@spec strict_policy() :: Nous.Permissions.Policy.t()
Returns a strict policy where all tools require approval.