Understanding Tool Permission Policies in LM-Kit.NET
TL;DR
Tool Permission Policies are runtime access-control rules that govern which tools an AI agent is allowed to call, which tools require human approval, and which tools are denied outright. In LM-Kit.NET, the ToolPermissionPolicy class provides a fluent API for defining allow, deny, and approval-required rules by tool name, wildcard pattern, category, or risk level. Combined with IToolMetadata (which exposes each tool's category, side effects, risk level, and idempotency) and the ToolApprovalRequired event for human-in-the-loop workflows, permission policies enable enterprise-grade governance over agent tool access.
What are Tool Permission Policies?
Definition: A Tool Permission Policy is a set of rules that determine, at runtime, whether an agent is allowed to execute a given tool. Before every tool invocation, the policy evaluates the tool against its rules and returns one of three outcomes: Allowed, Denied, or ApprovalRequired. This evaluation happens before any filter or tool code executes, making it the first line of defense.
Why Permission Policies Matter
- Security by Default: Prevent agents from calling dangerous tools (file deletion, process execution, email sending) unless explicitly authorized.
- Least Privilege: Grant agents access only to the tools they need. A customer-support agent does not need file system access. A data analysis agent does not need network tools.
- Human Oversight: Flag sensitive operations for human approval without blocking safe tool calls. This is critical for production deployments where autonomous agents handle real-world actions.
- Compliance: Meet organizational and regulatory requirements by auditing and controlling every tool invocation.
- Defense in Depth: Permission policies work alongside guardrails and filters, each enforcing safety at a different level of the pipeline.
The Policy Evaluation Model
Three Possible Outcomes
Every tool call passes through ToolPermissionPolicy.Evaluate(tool), which returns a ToolPermissionResult:
| Result | Meaning | What Happens |
|---|---|---|
Allowed |
Tool call proceeds automatically | Tool executes, result returns to model |
Denied |
Tool call is blocked | A ToolCallResultType.Denied message tells the model why |
ApprovalRequired |
Human must approve or deny | ToolApprovalRequired event fires; denied if no handler |
Evaluation Order
The policy evaluates rules in a strict priority order:
1. Explicit deny by name (highest priority)
2. Deny by wildcard pattern
3. Deny by category
4. Risk level gate (tool.RiskLevel > MaxRiskLevel)
5. Approval by name
6. Approval by wildcard pattern
7. Approval by category
8. Allow by name
9. Allow by wildcard pattern
10. Allow by category
11. DefaultAction (lowest priority: Allow or Deny)
This means a deny always wins over an allow, and an approval requirement wins over an implicit allow. This design ensures that restrictive rules cannot be accidentally overridden by permissive ones.
Tool Metadata: The Foundation for Policies
Every LM-Kit.NET built-in tool implements IToolMetadata, which exposes security-relevant properties that the policy engine uses for evaluation:
| Property | Type | Description |
|---|---|---|
Category |
string |
Tool family: "data", "document", "io", "net", "numeric", "security", "text", "utility" |
SideEffect |
ToolSideEffect |
What the tool does to the world: None, LocalRead, LocalWrite, NetworkRead, NetworkWrite, Irreversible |
RiskLevel |
ToolRiskLevel |
How dangerous the tool is: Low, Medium, High, Critical |
DefaultApproval |
ToolApprovalMode |
Recommended approval stance: Never, Conditional, Always |
IsIdempotent |
bool |
Whether calling the tool twice produces the same result |
IsReadOnly |
bool |
Whether the tool has no side effects on external state |
Custom tools that implement IToolMetadata automatically benefit from category-level and risk-level policy rules.
Practical Application in LM-Kit.NET SDK
Building a Permission Policy
The ToolPermissionPolicy class uses a fluent API. All methods return this for chaining:
using LMKit.Agents.Tools;
using LMKit.Agents.Tools.BuiltIn;
// Whitelist mode: deny everything by default, then allow selectively
var strictPolicy = new ToolPermissionPolicy()
{
DefaultAction = ToolPermissionAction.Deny
};
strictPolicy
.AllowCategory("data", "text", "numeric", "utility") // Safe categories
.Allow("websearch") // Allow one net tool
.RequireApproval("filesystem_*") // Require approval for all filesystem tools
.Deny("filesystem_delete"); // Always deny file deletion
// Permissive mode: allow everything, then restrict
var permissivePolicy = new ToolPermissionPolicy()
.DenyCategory("io") // Block all IO tools
.Deny("process_*") // Block all process tools
.SetMaxRiskLevel(ToolRiskLevel.Medium) // Block High and Critical tools
.RequireApprovalForCategory("net"); // Require approval for network tools
Attaching a Policy to an Agent
using LMKit.Model;
using LMKit.Agents;
using LMKit.Agents.Tools;
using LMKit.Agents.Tools.BuiltIn;
var model = LM.LoadFromModelID("glm4.7-flash");
var policy = new ToolPermissionPolicy()
.AllowCategory("data", "text", "numeric", "utility", "security")
.Allow("filesystem_read", "filesystem_list")
.Deny("filesystem_delete", "filesystem_write")
.RequireApproval("http_*")
.SetMaxRiskLevel(ToolRiskLevel.High);
var agent = Agent.CreateBuilder(model)
.WithTools(tools =>
{
// Register all built-in tools
foreach (var tool in BuiltInTools.GetAll())
tools.Register(tool);
})
.WithPermissionPolicy(policy)
.Build();
Human-in-the-Loop Approval
using LMKit.Agents;
using LMKit.TextGeneration.Events;
using var executor = new AgentExecutor();
// Subscribe to the approval event
executor.ToolApprovalRequired += (sender, e) =>
{
Console.WriteLine($"Tool: {e.ToolCall.Name}");
Console.WriteLine($" Risk: {e.RiskLevel}");
Console.WriteLine($" Effect: {e.SideEffect}");
Console.Write("Approve? (y/n): ");
if (Console.ReadLine()?.Trim().ToLower() == "y")
{
e.Approved = true;
}
else
{
e.Approved = false;
e.DenialReason = "User declined the operation.";
}
};
// If no handler is subscribed, ApprovalRequired tools are denied by default
Attaching a Policy to a Conversation
using LMKit.Model;
using LMKit.TextGeneration;
using LMKit.Agents.Tools;
var model = LM.LoadFromModelID("gemma3:12b");
using var chat = new MultiTurnConversation(model);
// Set the policy directly on the tool registry
chat.Tools.PermissionPolicy = new ToolPermissionPolicy()
.AllowCategory("data", "numeric")
.Deny("*"); // Deny everything else
// Subscribe to approval events on the conversation
chat.ToolApprovalRequired += (sender, e) =>
{
Console.Write($"Allow {e.ToolCall.Name}? ");
e.Approved = Console.ReadLine()?.Trim() == "y";
};
Common Policy Patterns
Safe Chat Profile
Only pure computation tools, no external effects:
var chatPolicy = new ToolPermissionPolicy()
.AllowCategory("data", "text", "numeric", "utility", "security")
.DenyCategory("io", "net")
.SetMaxRiskLevel(ToolRiskLevel.Low);
Developer Assistant Profile
Read access to files and web, approval for writes:
var devPolicy = new ToolPermissionPolicy()
.AllowCategory("data", "text", "numeric", "utility", "security")
.Allow("filesystem_read", "filesystem_list", "filesystem_search")
.Deny("filesystem_delete")
.RequireApproval("filesystem_write", "filesystem_move", "filesystem_copy")
.Allow("http_get", "http_head", "websearch")
.Deny("http_post", "http_put", "http_delete")
.RequireApproval("process_*");
Document Processing Profile
Document tools plus read-only IO:
var docPolicy = new ToolPermissionPolicy()
{
DefaultAction = ToolPermissionAction.Deny
};
docPolicy
.AllowCategory("data", "document", "text")
.Allow("filesystem_read")
.SetMaxRiskLevel(ToolRiskLevel.Medium);
Policy, Filters, and Guardrails: How They Relate
User prompt
|
v
+---------------------------+
| Prompt Filters | (content moderation, RAG injection)
+---------------------------+
|
v
[LLM Inference]
|
v (model requests a tool call)
+---------------------------+
| Permission Policy | <-- Evaluates FIRST: Allow / Deny / ApprovalRequired
+---------------------------+
|
v (if Allowed or Approved)
+---------------------------+
| Tool Invocation Filters | (logging, rate limiting, caching)
+---------------------------+
|
v
[Tool Execution]
|
v
+---------------------------+
| Completion Filters | (output validation, moderation)
+---------------------------+
|
v
Response
The permission policy is the gatekeeper. Filters provide observability and transformation. Guardrails are the broader safety strategy that encompasses both.
Key Terms
- ToolPermissionPolicy: The class that defines allow, deny, and approval rules for tool access.
- ToolPermissionResult: The outcome of policy evaluation:
Allowed,Denied, orApprovalRequired. - ToolPermissionAction: The default policy stance:
Allow(permissive) orDeny(whitelist mode). - ToolRiskLevel: Classification of tool danger:
Low,Medium,High,Critical. - ToolSideEffect: What the tool does to external state:
None,LocalRead,LocalWrite,NetworkRead,NetworkWrite,Irreversible. - ToolApprovalMode: Default approval recommendation:
Never,Conditional,Always. - IToolMetadata: Interface exposing security-relevant metadata used by the policy engine.
- ToolApprovalRequired: Event that fires when a tool call needs human approval; denied if no handler is subscribed.
- Wildcard Pattern: Name matching with
*and?for domain-level control (e.g.,filesystem_*matches all filesystem tools).
Related API Documentation
ToolPermissionPolicy: Fluent policy builder withAllow(),Deny(),RequireApproval(), and category/risk methodsIToolMetadata: Interface for tool security metadataToolPermissionResult: Evaluation outcome enumToolRiskLevel: Risk classification enumToolSideEffect: Side effect classification enumToolApprovalRequestEventArgs: Event args for human-in-the-loop approvalToolRegistry: Tool collection withPermissionPolicypropertyBuiltInTools: Factory class withGetByMaxRisk(),GetByCategory(),GetReadOnly()query methods
Related Glossary Topics
- AI Agent Tools: The tools that permission policies govern
- AI Agent Guardrails: The broader safety framework that includes policies
- Filters and Middleware: Composable interceptors that run after policy evaluation
- Function Calling: The tool-calling mechanism that policies control
- AI Agents: The autonomous systems that operate under policy constraints
- AI Agent Execution: The runtime lifecycle where policies are enforced
- Model Context Protocol (MCP): External tool catalogs that also respect permission policies
External Resources
- OWASP Top 10 for LLM Applications: Security risks that permission policies help mitigate
- Principle of Least Privilege (NIST): The security principle underlying permission policies
- Secure Agent Tool Access (How-To): Step-by-step permission policy guide
- Intercept and Control Tool Invocations (How-To): Combining policies with invocation events
Summary
Tool Permission Policies are the access-control layer that governs which tools an AI agent can invoke. In LM-Kit.NET, the ToolPermissionPolicy class provides a fluent API supporting Allow(), Deny(), RequireApproval(), category-level rules, wildcard patterns, and risk-level gates. Every built-in tool exposes IToolMetadata with its category, side effect type, risk level, and approval mode, enabling fine-grained, metadata-driven governance. When a policy returns ApprovalRequired, the ToolApprovalRequired event enables human-in-the-loop workflows. Combined with filters and guardrails, permission policies form the security backbone of production agent deployments, enforcing the principle of least privilege across every tool invocation.