From 323ab1d18049db3a238b404cb16c31c493ea732b Mon Sep 17 00:00:00 2001 From: maxpetrusenkoagent Date: Sat, 13 Jun 2026 00:06:17 -0400 Subject: [PATCH 1/4] docs: document ATR pre-tool hook path --- docs/en/learn/tool-hooks.mdx | 56 +++++++++++++++++++ .../hooks/test_tool_hooks_documentation.py | 31 ++++++++++ 2 files changed, 87 insertions(+) create mode 100644 lib/crewai/tests/hooks/test_tool_hooks_documentation.py diff --git a/docs/en/learn/tool-hooks.mdx b/docs/en/learn/tool-hooks.mdx index d1d727a5c9..9b2521c878 100644 --- a/docs/en/learn/tool-hooks.mdx +++ b/docs/en/learn/tool-hooks.mdx @@ -175,6 +175,62 @@ def safety_check(context: ToolCallHookContext) -> bool | None: return None ``` +#### Agent Threat Rules pre-tool scanner + +[Agent Threat Rules](https://github.com/Agent-Threat-Rule/agent-threat-rules) (ATR) is a catalog-driven rule set for known AI agent threats such as prompt injection, tool poisoning, context exfiltration, and privilege escalation. A recommended CrewAI integration path is a `@before_tool_call` hook: at this point the agent has already selected a concrete tool and concrete arguments, but the tool has not executed yet. + +This keeps ATR outside CrewAI's core dependency tree while giving scanners the full pre-tool context they need: + +- `context.tool_name` identifies the intended action +- `context.tool_input` contains the concrete arguments to scan +- `context.agent`, `context.task`, and `context.crew` provide execution context and access to each object's `security_config` +- The hook can return `False` to block execution before a risky tool call runs + +```python +from crewai.hooks import ToolCallHookContext, before_tool_call + + +def scan_with_agent_threat_rules(payload: dict) -> list[str]: + """Call your ATR adapter and return matched rule IDs.""" + # Example adapter boundary. Load ATR/pyatr in your app or optional integration + # package, then pass tool intent plus security metadata to the scanner. + return [] + + +@before_tool_call +def scan_tool_intent_with_atr(context: ToolCallHookContext) -> bool | None: + payload = { + "tool_name": context.tool_name, + "tool_input": context.tool_input, + "agent_role": context.agent.role if context.agent else None, + "agent_fingerprint": ( + context.agent.security_config.fingerprint.uuid_str + if context.agent and context.agent.security_config + else None + ), + "task_description": context.task.description if context.task else None, + "task_fingerprint": ( + context.task.security_config.fingerprint.uuid_str + if context.task and context.task.security_config + else None + ), + "crew_fingerprint": ( + context.crew.security_config.fingerprint.uuid_str + if context.crew and context.crew.security_config + else None + ), + } + + matched_rule_ids = scan_with_agent_threat_rules(payload) + if matched_rule_ids: + print(f"Blocked by Agent Threat Rules: {matched_rule_ids}") + return False + + return None +``` + +For credential brokering or secret access checks, attach the credential metadata your application is about to use to the same payload before scanning. That lets ATR-style catalog checks inspect both the action intent and the sensitive context in scope without requiring CrewAI to vendor the ATR rule corpus. + ### 2. Human Approval Gate ```python diff --git a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py new file mode 100644 index 0000000000..ae200404ba --- /dev/null +++ b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from pathlib import Path + + +DOCS_ROOT = Path(__file__).parents[4] / "docs" +TOOL_HOOKS_DOC = DOCS_ROOT / "en" / "learn" / "tool-hooks.mdx" + + +def test_tool_hooks_document_agent_threat_rules_integration_path() -> None: + """Document the pre-tool hook path for Agent Threat Rules scanners.""" + content = TOOL_HOOKS_DOC.read_text(encoding="utf-8") + + section_start = content.index("#### Agent Threat Rules pre-tool scanner") + section_end = content.index("### 2. Human Approval Gate", section_start) + atr_section = content[section_start:section_end] + + assert "Agent Threat Rules" in atr_section + assert "A recommended CrewAI integration path" in atr_section + assert "@before_tool_call" in atr_section + assert "scan_tool_intent_with_atr" in atr_section + assert "scan_with_agent_threat_rules" in atr_section + assert "context.tool_name" in atr_section + assert "context.tool_input" in atr_section + assert "context.agent" in atr_section + assert "context.task" in atr_section + assert "context.crew" in atr_section + assert "agent_fingerprint" in atr_section + assert "task_fingerprint" in atr_section + assert "crew_fingerprint" in atr_section + assert "return False" in atr_section From 7495f14e341a088c670e21a565a0d139a455c644 Mon Sep 17 00:00:00 2001 From: maxpetrusenkoagent Date: Sat, 13 Jun 2026 00:12:36 -0400 Subject: [PATCH 2/4] test: compile ATR tool hook docs example --- docs/en/learn/tool-hooks.mdx | 12 ++++++------ .../tests/hooks/test_tool_hooks_documentation.py | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/en/learn/tool-hooks.mdx b/docs/en/learn/tool-hooks.mdx index 9b2521c878..33613ca15f 100644 --- a/docs/en/learn/tool-hooks.mdx +++ b/docs/en/learn/tool-hooks.mdx @@ -204,19 +204,19 @@ def scan_tool_intent_with_atr(context: ToolCallHookContext) -> bool | None: "tool_input": context.tool_input, "agent_role": context.agent.role if context.agent else None, "agent_fingerprint": ( - context.agent.security_config.fingerprint.uuid_str - if context.agent and context.agent.security_config + context.agent.fingerprint.uuid_str + if context.agent and context.agent.fingerprint else None ), "task_description": context.task.description if context.task else None, "task_fingerprint": ( - context.task.security_config.fingerprint.uuid_str - if context.task and context.task.security_config + context.task.fingerprint.uuid_str + if context.task and context.task.fingerprint else None ), "crew_fingerprint": ( - context.crew.security_config.fingerprint.uuid_str - if context.crew and context.crew.security_config + context.crew.fingerprint.uuid_str + if context.crew and context.crew.fingerprint else None ), } diff --git a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py index ae200404ba..3542b535a7 100644 --- a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py +++ b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py @@ -1,5 +1,6 @@ from __future__ import annotations +import ast from pathlib import Path @@ -29,3 +30,6 @@ def test_tool_hooks_document_agent_threat_rules_integration_path() -> None: assert "task_fingerprint" in atr_section assert "crew_fingerprint" in atr_section assert "return False" in atr_section + + python_block = atr_section.split("```python", 1)[1].split("```", 1)[0] + ast.parse(python_block) From b74cf1030d2d623066bfccb616969b5c53971a40 Mon Sep 17 00:00:00 2001 From: maxpetrusenkoagent Date: Sat, 13 Jun 2026 00:17:00 -0400 Subject: [PATCH 3/4] fix: keep ATR docs example adapter-compatible --- docs/en/learn/tool-hooks.mdx | 12 ++++++------ .../tests/hooks/test_tool_hooks_documentation.py | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/en/learn/tool-hooks.mdx b/docs/en/learn/tool-hooks.mdx index 33613ca15f..9b2521c878 100644 --- a/docs/en/learn/tool-hooks.mdx +++ b/docs/en/learn/tool-hooks.mdx @@ -204,19 +204,19 @@ def scan_tool_intent_with_atr(context: ToolCallHookContext) -> bool | None: "tool_input": context.tool_input, "agent_role": context.agent.role if context.agent else None, "agent_fingerprint": ( - context.agent.fingerprint.uuid_str - if context.agent and context.agent.fingerprint + context.agent.security_config.fingerprint.uuid_str + if context.agent and context.agent.security_config else None ), "task_description": context.task.description if context.task else None, "task_fingerprint": ( - context.task.fingerprint.uuid_str - if context.task and context.task.fingerprint + context.task.security_config.fingerprint.uuid_str + if context.task and context.task.security_config else None ), "crew_fingerprint": ( - context.crew.fingerprint.uuid_str - if context.crew and context.crew.fingerprint + context.crew.security_config.fingerprint.uuid_str + if context.crew and context.crew.security_config else None ), } diff --git a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py index 3542b535a7..5b2e7bdeeb 100644 --- a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py +++ b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py @@ -29,6 +29,7 @@ def test_tool_hooks_document_agent_threat_rules_integration_path() -> None: assert "agent_fingerprint" in atr_section assert "task_fingerprint" in atr_section assert "crew_fingerprint" in atr_section + assert "security_config.fingerprint" in atr_section assert "return False" in atr_section python_block = atr_section.split("```python", 1)[1].split("```", 1)[0] From c3b329d6995cef2dc199098bd7cc3df100fc3b6b Mon Sep 17 00:00:00 2001 From: maxpetrusenkoagent <[REDACTED EMAIL]> Date: Sun, 28 Jun 2026 22:06:13 -0400 Subject: [PATCH 4/4] fix: keep ATR docs on edge docs path --- docs/edge/en/learn/tool-hooks.mdx | 56 +++++++++++++++++++ docs/v1.13.0/en/learn/tool-hooks.mdx | 56 ------------------- .../hooks/test_tool_hooks_documentation.py | 2 +- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/docs/edge/en/learn/tool-hooks.mdx b/docs/edge/en/learn/tool-hooks.mdx index 489463e812..76540b09c2 100644 --- a/docs/edge/en/learn/tool-hooks.mdx +++ b/docs/edge/en/learn/tool-hooks.mdx @@ -178,6 +178,62 @@ def safety_check(context: ToolCallHookContext) -> bool | None: return None ``` +#### Agent Threat Rules pre-tool scanner + +[Agent Threat Rules](https://github.com/Agent-Threat-Rule/agent-threat-rules) (ATR) is a catalog-driven rule set for known AI agent threats such as prompt injection, tool poisoning, context exfiltration, and privilege escalation. A recommended CrewAI integration path is a `@before_tool_call` hook: at this point the agent has already selected a concrete tool and concrete arguments, but the tool has not executed yet. + +This keeps ATR outside CrewAI's core dependency tree while giving scanners the full pre-tool context they need: + +- `context.tool_name` identifies the intended action +- `context.tool_input` contains the concrete arguments to scan +- `context.agent`, `context.task`, and `context.crew` provide execution context and access to each object's `security_config` +- The hook can return `False` to block execution before a risky tool call runs + +```python +from crewai.hooks import ToolCallHookContext, before_tool_call + + +def scan_with_agent_threat_rules(payload: dict) -> list[str]: + """Call your ATR adapter and return matched rule IDs.""" + # Example adapter boundary. Load ATR/pyatr in your app or optional integration + # package, then pass tool intent plus security metadata to the scanner. + return [] + + +@before_tool_call +def scan_tool_intent_with_atr(context: ToolCallHookContext) -> bool | None: + payload = { + "tool_name": context.tool_name, + "tool_input": context.tool_input, + "agent_role": context.agent.role if context.agent else None, + "agent_fingerprint": ( + context.agent.security_config.fingerprint.uuid_str + if context.agent and context.agent.security_config + else None + ), + "task_description": context.task.description if context.task else None, + "task_fingerprint": ( + context.task.security_config.fingerprint.uuid_str + if context.task and context.task.security_config + else None + ), + "crew_fingerprint": ( + context.crew.security_config.fingerprint.uuid_str + if context.crew and context.crew.security_config + else None + ), + } + + matched_rule_ids = scan_with_agent_threat_rules(payload) + if matched_rule_ids: + print(f"Blocked by Agent Threat Rules: {matched_rule_ids}") + return False + + return None +``` + +For credential brokering or secret access checks, attach the credential metadata your application is about to use to the same payload before scanning. That lets ATR-style catalog checks inspect both the action intent and the sensitive context in scope without requiring CrewAI to vendor the ATR rule corpus. + ### 2. Human Approval Gate ```python diff --git a/docs/v1.13.0/en/learn/tool-hooks.mdx b/docs/v1.13.0/en/learn/tool-hooks.mdx index 9b2521c878..d1d727a5c9 100644 --- a/docs/v1.13.0/en/learn/tool-hooks.mdx +++ b/docs/v1.13.0/en/learn/tool-hooks.mdx @@ -175,62 +175,6 @@ def safety_check(context: ToolCallHookContext) -> bool | None: return None ``` -#### Agent Threat Rules pre-tool scanner - -[Agent Threat Rules](https://github.com/Agent-Threat-Rule/agent-threat-rules) (ATR) is a catalog-driven rule set for known AI agent threats such as prompt injection, tool poisoning, context exfiltration, and privilege escalation. A recommended CrewAI integration path is a `@before_tool_call` hook: at this point the agent has already selected a concrete tool and concrete arguments, but the tool has not executed yet. - -This keeps ATR outside CrewAI's core dependency tree while giving scanners the full pre-tool context they need: - -- `context.tool_name` identifies the intended action -- `context.tool_input` contains the concrete arguments to scan -- `context.agent`, `context.task`, and `context.crew` provide execution context and access to each object's `security_config` -- The hook can return `False` to block execution before a risky tool call runs - -```python -from crewai.hooks import ToolCallHookContext, before_tool_call - - -def scan_with_agent_threat_rules(payload: dict) -> list[str]: - """Call your ATR adapter and return matched rule IDs.""" - # Example adapter boundary. Load ATR/pyatr in your app or optional integration - # package, then pass tool intent plus security metadata to the scanner. - return [] - - -@before_tool_call -def scan_tool_intent_with_atr(context: ToolCallHookContext) -> bool | None: - payload = { - "tool_name": context.tool_name, - "tool_input": context.tool_input, - "agent_role": context.agent.role if context.agent else None, - "agent_fingerprint": ( - context.agent.security_config.fingerprint.uuid_str - if context.agent and context.agent.security_config - else None - ), - "task_description": context.task.description if context.task else None, - "task_fingerprint": ( - context.task.security_config.fingerprint.uuid_str - if context.task and context.task.security_config - else None - ), - "crew_fingerprint": ( - context.crew.security_config.fingerprint.uuid_str - if context.crew and context.crew.security_config - else None - ), - } - - matched_rule_ids = scan_with_agent_threat_rules(payload) - if matched_rule_ids: - print(f"Blocked by Agent Threat Rules: {matched_rule_ids}") - return False - - return None -``` - -For credential brokering or secret access checks, attach the credential metadata your application is about to use to the same payload before scanning. That lets ATR-style catalog checks inspect both the action intent and the sensitive context in scope without requiring CrewAI to vendor the ATR rule corpus. - ### 2. Human Approval Gate ```python diff --git a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py index 5b2e7bdeeb..c73ddf1b82 100644 --- a/lib/crewai/tests/hooks/test_tool_hooks_documentation.py +++ b/lib/crewai/tests/hooks/test_tool_hooks_documentation.py @@ -5,7 +5,7 @@ DOCS_ROOT = Path(__file__).parents[4] / "docs" -TOOL_HOOKS_DOC = DOCS_ROOT / "en" / "learn" / "tool-hooks.mdx" +TOOL_HOOKS_DOC = DOCS_ROOT / "edge" / "en" / "learn" / "tool-hooks.mdx" def test_tool_hooks_document_agent_threat_rules_integration_path() -> None: