ADK Agent Structure Validation Hook
Validates ADK agent directory structure before running agents.
Trigger
- Event:
PreToolUse - Pattern: Commands containing
adk run,adk eval,adk web
Validation Rules
Required Structure
agent_name/
├── __init__.py # Must contain: from . import agent
└── agent.py # Must define: root_agent OR app
Validation Checks
- Directory exists - Agent path is valid directory
__init__.pyexists - Required for Python module__init__.pyimports agent - Containsfrom . import agentagent.pyexists - Contains agent definition- Defines root_agent or app - Entry point for ADK
Implementation
#!/usr/bin/env python3
"""ADK Agent Structure Validation Hook"""
import json
import os
import re
import sys
def validate_adk_agent(agent_path: str) -> list[str]:
"""Validate ADK agent directory structure."""
errors = []
# Check directory exists
if not os.path.isdir(agent_path):
errors.append(f"Agent path is not a directory: {agent_path}")
return errors
# Check __init__.py
init_path = os.path.join(agent_path, "__init__.py")
if not os.path.exists(init_path):
errors.append(f"Missing __init__.py in {agent_path}")
else:
with open(init_path, "r") as f:
init_content = f.read()
if "from . import agent" not in init_content and "from .agent import" not in init_content:
errors.append("__init__.py must contain 'from . import agent'")
# Check agent.py
agent_file = os.path.join(agent_path, "agent.py")
if not os.path.exists(agent_file):
errors.append(f"Missing agent.py in {agent_path}")
else:
with open(agent_file, "r") as f:
agent_content = f.read()
# Check for root_agent or app definition
has_root_agent = re.search(r"^root_agent\s*=", agent_content, re.MULTILINE)
has_app = re.search(r"^app\s*=", agent_content, re.MULTILINE)
if not has_root_agent and not has_app:
errors.append("agent.py must define 'root_agent' or 'app'")
return errors
def extract_agent_path(command: str) -> str | None:
"""Extract agent path from ADK command."""
# Patterns: adk run path/to/agent, adk web path/, adk eval path/agent
patterns = [
r"adk\s+run\s+([^\s]+)",
r"adk\s+web\s+([^\s]+)",
r"adk\s+eval\s+([^\s]+)",
]
for pattern in patterns:
match = re.search(pattern, command)
if match:
return match.group(1)
return None
def main():
"""Hook entry point."""
input_data = json.load(sys.stdin)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
# Only validate Bash commands with adk
if tool_name != "Bash":
print(json.dumps({"decision": "allow"}))
return
command = tool_input.get("command", "")
# Check if it's an ADK command
if not re.search(r"adk\s+(run|web|eval)", command):
print(json.dumps({"decision": "allow"}))
return
# Extract agent path
agent_path = extract_agent_path(command)
if not agent_path:
print(json.dumps({"decision": "allow"}))
return
# Expand home directory
agent_path = os.path.expanduser(agent_path)
# For adk web, path might be a parent directory containing multiple agents
if "adk web" in command or "adk api_server" in command:
# Just check directory exists for web/api
if not os.path.isdir(agent_path):
print(json.dumps({
"decision": "block",
"reason": f"Agents directory not found: {agent_path}"
}))
else:
print(json.dumps({"decision": "allow"}))
return
# Validate agent structure
errors = validate_adk_agent(agent_path)
if errors:
print(json.dumps({
"decision": "block",
"reason": f"ADK agent validation failed:\n" + "\n".join(f" - {e}" for e in errors)
}))
else:
print(json.dumps({"decision": "allow"}))
if __name__ == "__main__":
main()
Configuration
Add to ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"pattern": "adk (run|web|eval)",
"command": "python3 ~/.coditect/hooks/adk-agent-structure-validation.py"
}
]
}
}
Common Errors
| Error | Cause | Fix |
|---|---|---|
| Not a directory | Invalid path | Check agent path |
Missing __init__.py | Incomplete setup | Create file with import |
| Missing import | Wrong init content | Add from . import agent |
| Missing agent.py | No agent definition | Create agent.py |
| No root_agent/app | Missing entry point | Define root_agent = Agent(...) |
Quick Fix Template
# __init__.py
from . import agent
# agent.py
from google.adk.agents import Agent
root_agent = Agent(
name="my_agent",
model="gemini-2.5-flash",
instruction="You are a helpful assistant.",
)
Version: 1.0.0 Created: 2026-01-13