LemonRouter.Policy (lemon_router v0.1.0)

View Source

Policy merging for tool execution.

Merges tool policies from multiple sources:

  • Agent default policy
  • Channel policy (groups can be stricter)
  • Session overrides
  • Runtime overrides (operator)

Policy Structure

A tool policy is a map with the following optional keys:

%{
  # Approval requirements per tool
  approvals: %{
    "bash" => :always,        # always require approval
    "write" => :dangerous,    # require for dangerous actions
    "read" => :never          # never require approval
  },
  # Blocked tools (cannot be used at all)
  blocked_tools: ["process_kill", "exec_raw"],
  # Allowed commands (whitelist for bash/exec)
  allowed_commands: ["git", "npm", "cargo"],
  # Blocked commands (blacklist)
  blocked_commands: ["rm -rf /", "sudo"],
  # Max file size for write operations
  max_file_size: 1_048_576,
  # Sandbox mode
  sandbox: true
}

Summary

Functions

Check if a tool requires approval based on the policy.

Check if a command is allowed by the policy.

Merge two tool policies.

Resolve the effective tool policy for a run.

Check if a tool is blocked by the policy.

Functions

approval_required?(policy, tool)

@spec approval_required?(map(), binary()) :: :always | :dangerous | :never | :default

Check if a tool requires approval based on the policy.

Returns:

  • :always - Always require approval
  • :dangerous - Require approval only for dangerous actions
  • :never - Never require approval
  • :default - Use tool's default behavior

command_allowed?(policy, command)

@spec command_allowed?(map(), binary()) :: boolean()

Check if a command is allowed by the policy.

If no allowed_commands list is specified, all commands are allowed. If a blocked_commands list exists, those are always blocked.

merge(policy_a, policy_b)

@spec merge(tool_policy_a :: map(), tool_policy_b :: map()) :: map()

Merge two tool policies.

The second policy takes precedence, with some special handling:

  • Lists are concatenated (e.g., allowed_commands)
  • Maps are deep merged
  • Booleans use the stricter value for "deny" semantics

resolve_for_run(params)

@spec resolve_for_run(map()) :: map()

Resolve the effective tool policy for a run.

Parameters

  • :agent_id - Agent identifier
  • :session_key - Session key
  • :origin - Request origin (:channel, :control_plane, :cron, :node)
  • :channel_context - Optional channel-specific context

tool_blocked?(policy, tool)

@spec tool_blocked?(map(), binary()) :: boolean()

Check if a tool is blocked by the policy.