Policy — ai-tool-guard/policy¶
The policy module provides the rule evaluation engine, ergonomic rule builders, preset bundles, and a simulation runner for dry-run analysis.
import {
evaluatePolicy,
allow,
deny,
requireApproval,
defaultPolicy,
readOnlyPolicy,
simulate,
} from "ai-tool-guard/policy";
Functions¶
evaluatePolicy¶
async function evaluatePolicy(
ctx: PolicyContext,
options: GuardOptions,
toolConfig?: { riskLevel?: RiskLevel; riskCategories?: RiskCategory[] },
): Promise<DecisionRecord>
Evaluate a tool call against the configured policy rules and/or external backend.
Evaluation order:
- If a
PolicyBackendis configured, delegate to it first. - Evaluate built-in
PolicyRuleentries in descending priority order. - Merge results using severity escalation:
deny>require-approval>allow. - If no rule matches, default to
"allow".
The result is always a full DecisionRecord regardless of verdict.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ctx |
PolicyContext |
Yes | Tool call context: name, args, user attributes, conversation |
options |
GuardOptions |
Yes | Guard configuration containing rules and/or backend |
toolConfig |
{ riskLevel?: RiskLevel; riskCategories?: RiskCategory[] } |
No | Per-tool risk metadata used when evaluating risk-level-based rules |
Returns Promise<DecisionRecord>
allow¶
function allow(opts: {
tools: string | string[];
riskLevels?: RiskLevel[];
condition?: (ctx: PolicyContext) => boolean | Promise<boolean>;
description?: string;
priority?: number;
}): PolicyRule
Create a PolicyRule with verdict "allow".
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
tools |
string \| string[] |
Yes | Tool name glob pattern(s). Use "*" for all tools. |
riskLevels |
RiskLevel[] |
No | Restrict to tools with these risk levels |
condition |
(ctx: PolicyContext) => boolean \| Promise<boolean> |
No | Predicate for attribute-based matching |
description |
string |
No | Human-readable description recorded in the decision |
priority |
number |
No | Higher values are evaluated first. Default: 0 |
Returns PolicyRule
deny¶
function deny(opts: {
tools: string | string[];
riskLevels?: RiskLevel[];
condition?: (ctx: PolicyContext) => boolean | Promise<boolean>;
description?: string;
priority?: number;
}): PolicyRule
Create a PolicyRule with verdict "deny". Same options shape as allow().
Returns PolicyRule
requireApproval¶
function requireApproval(opts: {
tools: string | string[];
riskLevels?: RiskLevel[];
condition?: (ctx: PolicyContext) => boolean | Promise<boolean>;
description?: string;
priority?: number;
}): PolicyRule
Create a PolicyRule with verdict "require-approval". Same options shape as
allow().
Returns PolicyRule
defaultPolicy¶
Return a preset rule bundle with three rules:
allowall tools withriskLevel: "low"requireApprovalfor tools withriskLevel: "medium"denytools withriskLevel: "high"or"critical"
All three rules use tools: "*" and priority: 0.
Returns PolicyRule[]
Example
const guard = createToolGuard({
rules: defaultPolicy(),
onApprovalRequired: async (token) => handleApproval(token),
});
readOnlyPolicy¶
Return a two-rule bundle that allows a specified set of read-only tools and denies everything else.
| Parameter | Type | Required | Description |
|---|---|---|---|
readToolPatterns |
string[] |
Yes | Glob patterns for tools that should be allowed |
Returns PolicyRule[] — [allow({ tools: readToolPatterns, priority: 10 }), deny({ tools: "*", priority: 0 })]
Example
simulate¶
async function simulate(
trace: RecordedToolCall[],
options: GuardOptions,
toolConfigs?: Record<string, ToolGuardConfig>,
): Promise<SimulationResult>
Run a dry-run policy evaluation over a recorded trace of tool calls. No tools are
executed. Every call produces a DecisionRecord with dryRun: true.
| Parameter | Type | Required | Description |
|---|---|---|---|
trace |
RecordedToolCall[] |
Yes | Sequence of recorded tool calls to evaluate |
options |
GuardOptions |
Yes | The policy configuration to evaluate against |
toolConfigs |
Record<string, ToolGuardConfig> |
No | Per-tool risk metadata for the simulation |
Returns Promise<SimulationResult>
Example
const result = await simulate(recordedCalls, { rules: defaultPolicy() });
console.log(result.summary);
// { total: 10, allowed: 7, denied: 2, requireApproval: 1 }
Interfaces¶
PolicyRule¶
Atomic unit of the built-in policy engine.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | Stable identifier used in DecisionRecord.matchedRules |
description |
string |
No | Human-readable explanation shown in decision records |
toolPatterns |
string[] |
Yes | Glob patterns matched against PolicyContext.toolName |
riskLevels |
RiskLevel[] |
No | If set, rule only matches tools with one of these risk levels |
verdict |
DecisionVerdict |
Yes | Action to take: "allow", "deny", or "require-approval" |
condition |
(ctx: PolicyContext) => boolean \| Promise<boolean> |
No | Optional async predicate; rule skipped when it returns false |
priority |
number |
No | Evaluation order; higher = evaluated first. Default: 0 |
PolicyBackend¶
Adapter interface for delegating decisions to an external policy engine such as OPA or Cedar.
interface PolicyBackend {
name: string;
evaluate(ctx: PolicyContext): Promise<PolicyBackendResult>;
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
Yes | Unique name used in logging and tracing |
evaluate |
(ctx: PolicyContext) => Promise<PolicyBackendResult> |
Yes | Evaluate a tool invocation and return a verdict |
PolicyBackendResult¶
Result returned by PolicyBackend.evaluate().
| Field | Type | Required | Description |
|---|---|---|---|
verdict |
DecisionVerdict |
Yes | The verdict from the external engine |
reason |
string |
Yes | Human-readable explanation |
matchedRules |
string[] |
Yes | Rule IDs or names that matched in the external engine |
attributes |
Record<string, unknown> |
No | Additional attributes merged into the DecisionRecord |
PolicyContext¶
Context passed into every policy evaluation.
| Field | Type | Required | Description |
|---|---|---|---|
toolName |
string |
Yes | Name of the tool being invoked |
args |
Record<string, unknown> |
Yes | Arguments the model wants to pass |
userAttributes |
Record<string, unknown> |
Yes | Caller-supplied attributes (user id, roles, tenant, etc.) |
conversation |
ConversationContext |
No | Conversation-level metadata for contextual policies |
dryRun |
boolean |
No | When true, the engine is in simulation mode |
RecordedToolCall¶
A captured tool call used as input to simulate().
| Field | Type | Required | Description |
|---|---|---|---|
toolName |
string |
Yes | Name of the tool |
args |
Record<string, unknown> |
Yes | Arguments of the call |
userAttributes |
Record<string, unknown> |
No | User attribute overrides for this simulation entry |
SimulationResult¶
Aggregate output of simulate().
| Field | Type | Description |
|---|---|---|
decisions |
DecisionRecord[] |
All decision records produced, one per recorded call |
summary |
{ total: number; allowed: number; denied: number; requireApproval: number } |
Counts by verdict |
blocked |
Array<{ toolCall: RecordedToolCall; decision: DecisionRecord }> |
Calls that would have been denied or required approval |