Skip to main content

Policy framework for Claude Code and Cursor hooks

Project description

AI Agent Policies

PyPI

Policies turn your Cursor Rules or CLAUDE.md into hard guardrails which an AI Agent cannot simply ignore, or forget. They handle what to do when an agent wants to make a decision, along with other hooks-supported events. Policies can yield both decisions and guidance.

This framework supports Claude Code. Support for Cursor is in beta.

Why Policies

Automating Decisions

Rule files can be forgotten or ignored completely by LLMs. Policies are unavoidable:

if re.match(r'^terraform\s+apply(?:\s|$)', command):
    yield PolicyDecision(action=PolicyAction.DENY, reason="terraform apply is not allowed. Use `terraform plan` instead.")

if re.match(r'^terraform\s+(fmt|plan)(?:\s|$)', command):
    yield PolicyDecision(action=PolicyAction.ALLOW)

In the image below, the agent is denied by policy from running terraform apply. The agent can then make decisions on what to do next, in this case it outputs that it will attempt a terraform plan as per the policy recommendation.

Screenshot 2025-10-03 at 16 15 29

Automating Guidance

Aside from denying and allowing automatically, policies can also provide guidance through Post-* events:

if comment_to_code_overlap >= 0.4:
    yield PolicyHelper.guidance(
        "Ensure comments add value beyond describing what's obvious from the code. "
        "This comment may be redundant with the code it describes."
    )
    return

In the image below, an agent makes a change which includes a comment that is detected as being potentially redundant. The guidance from the snippet is given as feedback to the change, after which the agent by itself decides to remove the redundant comment.

Screenshot 2025-10-21 at 21 47 37

Usage

At DevLeaps we developed an internal policy set for AI Agents. To create your own, refer to the example server as a starting point The example server contains:

  • A basic server setup demonstrating the use of policies and middleware.
  • Rudimentary policies showcasing how to automatically deny, allow and provide guidance.
  • Rudimentary middleware showcasing how multi-command tool use could be handled.

To run the example server:

devleaps-policy-example-server

This starts a minimal server running just our example policies.

Architecture

graph TB
    subgraph "Developer Machine"
      Editor[Claude Code / Cursor]
        Client[devleaps-policy-client]
    end

    subgraph "Policy Server"
        Server[HTTP API]
        Policies[Your policies<br/>kubectl, terraform, git, python, etc.]
    end

    Editor -->|Hooks| Client
    Client --> Server
    Server -->|Events| Policies
    Policies -->|Decision and Guidance| Server
    Server --> Client
    Client -->|Decision and Guidance| Editor

Quick Start

Installation

Update your local profile with;

# Add the bin directory to $PATH
export PATH="$PATH:/path/to/agent-policies/bin/"

Running an Example Server

devleaps-policy-example-server

The example server runs on port 8338 by default and serves endpoints for both Claude Code and Cursor.

Configure Claude Code

Add devleaps-policy-client to your Claude Code hooks configuration in ~/.claude/settings.json:

Click to expand Claude Code configuration
{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "SubagentStop": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "Notification": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "PreCompact": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "matcher": "*",
            "type": "command",
            "command": "devleaps-policy-client"
          }
        ]
      }
    ]
  }
}

[!WARNING] Be aware when automatically allowing that Bash tools use strings can invole more than one underlying tool. Consider also commands such as find having unsafe options like -exec.

Configure Cursor

Create or edit ~/.cursor/hooks.json:

Click to expand Cursor configuration
{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      { "command": "devleaps-policy-client" }
    ],
    "beforeMCPExecution": [
      { "command": "devleaps-policy-client" }
    ],
    "afterFileEdit": [
      { "command": "devleaps-policy-client" }
    ],
    "beforeReadFile": [
      { "command": "devleaps-policy-client" }
    ],
    "beforeSubmitPrompt": [
      { "command": "devleaps-policy-client" }
    ],
    "stop": [
      { "command": "devleaps-policy-client" }
    ]
  }
}

The devleaps-policy-client command will forward hook events to the policy server running on localhost:8338.

[!WARNING] Be aware when automatically allowing that Bash tools use strings can invole more than one underlying tool. Consider also commands such as find having unsafe options like -exec.

Sessions

Each Claude Code or Cursor session receives a unique session_id. Policies can use this to track context across multiple hook events within the same session, enabling stateful policy decisions. See the session state utility to store and retrieve per-session data.

Configuration

The client supports centralized configuration via JSON files:

Home-level config (~/.agent-policies/config.json):

{
  "bundles": ["python", "git"],
  "editor": "claude-code",
  "server_url": "http://localhost:8338",
  "default_policy_behavior": "ask"
}

Project-level config (.agent-policies/config.json):

{
  "bundles": ["terraform"]
}

Configuration is merged with project settings overriding home settings.

Available fields:

  • bundles: List of enabled policy bundles (default: [])
  • editor: Editor name, ignored by client (default: claude-code)
  • server_url: Policy server endpoint (default: http://localhost:8338)

Policy Bundles

Policies can be organized into bundles to group related rules for specific workflows or project types. This allows you to compose different policy sets without having to manage separate server configurations.

How bundles work:

  • Universal policies (registered with bundle=None) are always enforced
  • Bundle-specific policies are only enforced when enabled in config
  • Multiple bundles can be enabled: set "bundles": ["bundle1", "bundle2"] in config
  • Bundles can coordinate through shared session state

See the uv example for a working one-rule bundle implementation.

Development

This project is built with uv.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

devleaps_agent_policies-1.0.5.tar.gz (51.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

devleaps_agent_policies-1.0.5-py3-none-any.whl (34.7 kB view details)

Uploaded Python 3

File details

Details for the file devleaps_agent_policies-1.0.5.tar.gz.

File metadata

  • Download URL: devleaps_agent_policies-1.0.5.tar.gz
  • Upload date:
  • Size: 51.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.22 {"installer":{"name":"uv","version":"0.9.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for devleaps_agent_policies-1.0.5.tar.gz
Algorithm Hash digest
SHA256 df8ff9f46768099fd540476e35e70075922d72da4169af473bc5a799bab35af9
MD5 1c71d22f7c82de9e714dcd582e8ae4fb
BLAKE2b-256 7e7daf0a1e6edbfa140c1a949c60058c11df24576a3459fcf9d6d2b25f707240

See more details on using hashes here.

File details

Details for the file devleaps_agent_policies-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: devleaps_agent_policies-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 34.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.22 {"installer":{"name":"uv","version":"0.9.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for devleaps_agent_policies-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 3c1820a838878b6f79a4d128fa3ee6c70ecdeaa29ea0991d7a1bd97117473661
MD5 9fabf3d05d507b79814da40dff47483c
BLAKE2b-256 c5b642360e68efe5d24f3de70053de589ab3e96ff14fb2c5bf1a12d7ac1f9fee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page