Skip to content

feat: add hooks system for agent lifecycle events#1601

Open
Raghavendiran-2002 wants to merge 1 commit intokagent-dev:mainfrom
Raghavendiran-2002:feat/hooks-system
Open

feat: add hooks system for agent lifecycle events#1601
Raghavendiran-2002 wants to merge 1 commit intokagent-dev:mainfrom
Raghavendiran-2002:feat/hooks-system

Conversation

@Raghavendiran-2002
Copy link
Copy Markdown
Contributor

Summary

Closes #1564

Implements a hooks system for kagent agents, similar to Claude Code / opencode hooks. This allows agent developers to
extend agent behavior (memory, PII redaction, tool policy, notifications, etc.) without modifying kagent core.

What's added

New CRD fields — hooks field on AgentSpec with HookSpec type supporting PreToolUse, PostToolUse,
SessionStart, and SessionEnd events
OCI container mounting — hooks are loaded from OCI images via an hooks-init init container into /hooks/,
reusing the same pattern as Skills. Duplicate refs are deduplicated (same image mounted once)
claude-command protocol — hooks read JSON from stdin, write JSON to stdout (or exit code 2 for errors).
PreToolUse hooks can approve or block tool calls
Python runtime integration — hooks are wired into ADK callbacks (before_tool_callback, after_tool_callback)
and session lifecycle points
Example agent spec

spec:
hooks:
- ref: ghcr.io/org/security-hooks:v1.0
event: PreToolUse
type: claude-command
matcher: "bash|shell_exec"
command: check-tool-use.sh
- ref: ghcr.io/org/security-hooks:v1.0
event: SessionStart
type: claude-command
command: inject-session-metadata.py

Files changed

  • go/api/v1alpha2/agent_types.go — HookSpec, HookEventType, HookProtocolType types + Hooks []HookSpec on AgentSpec
  • go/api/adk/types.go — HookConfig struct + Hooks field on AgentConfig
  • go/core/internal/controller/translator/agent/ — hooks init container builder, volume wiring, config translation
  • go/core/pkg/env/kagent.go — KAGENT_HOOKS_FOLDER env var
  • python/packages/kagent-adk/src/kagent/adk/_hooks.py — new hook runner (subprocess executor, pre/post-tool
    callbacks, session hooks)
  • python/packages/kagent-adk/src/kagent/adk/types.py — HookConfig dataclass + hooks field on AgentConfig

Test plan

  • All existing Go unit tests pass (make -C go test)
  • Golden file testdata/outputs/agent_with_hooks.json generated and reviewed — verifies deduplication, correct
    volume/env/config output
  • Go lint passes (make -C go lint)
  • Manual: deploy agent with hooks spec, verify hooks-init container runs and /hooks/ is populated
  • Manual: verify PreToolUse hook can block a tool call with {"decision": "block", "reason": "..."}

Signed-off-by: Raghavendiran-Github <raghavendiran46461@gmail.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a hooks system for kagent agents, enabling agent developers to extend agent behavior through lifecycle hooks (PreToolUse, PostToolUse, SessionStart, SessionEnd) without modifying the kagent core. Hooks are loaded from OCI container images and communicate via the "claude-command" protocol (JSON stdin/stdout).

Changes:

  • Added CRD types for hooks (HookSpec, HookEventType, HookProtocolType) with Go and Python serialization
  • Implemented hooks init container builder that deduplicates OCI refs and mounts hook images into /hooks
  • Created Python runtime hooks system with subprocess execution, regex matching, and callback composition with approval callbacks
  • Integrated hooks into agent lifecycle (SessionStart/SessionEnd) via the agent executor
  • Updated CRD and Helm chart definitions
  • Added comprehensive test data for end-to-end validation

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
go/api/v1alpha2/agent_types.go CRD types for hooks with validation
go/api/adk/types.go Go serialization of HookConfig
go/core/internal/controller/translator/agent/adk_api_translator.go Hooks init container builder and config translation
go/core/internal/controller/translator/agent/hooks-init.sh.tmpl Shell script template for OCI image mounting
go/core/pkg/env/kagent.go Added KAGENT_HOOKS_FOLDER env var
python/packages/kagent-adk/src/kagent/adk/types.py Python HookConfig and hooks integration with Agent
python/packages/kagent-adk/src/kagent/adk/_hooks.py New hook runtime with subprocess execution and callbacks
python/packages/kagent-adk/src/kagent/adk/_agent_executor.py SessionStart/SessionEnd hook invocation
python/packages/kagent-adk/src/kagent/adk/cli.py Setting hooks on agent instance
helm/kagent-crds/templates/kagent.dev_agents.yaml Updated CRD schema
go/api/config/crd/bases/kagent.dev_agents.yaml Updated CRD schema
go/core/internal/controller/translator/agent/testdata/ Test data for hooks validation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"""Return True if the hook's matcher regex matches tool_name, or no matcher is set."""
if not hook.matcher:
return True
return bool(re.search(hook.matcher, tool_name))
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _matches_tool function uses re.search() without error handling. If a user provides an invalid ECMAScript regex pattern in the hook's matcher field, this will raise a re.error exception and crash the tool callback, causing the agent to fail. Invalid regex patterns should be caught and logged, with the hook treated as non-matching or skipped to ensure the agent continues operating.

Suggested change
return bool(re.search(hook.matcher, tool_name))
try:
return bool(re.search(hook.matcher, tool_name))
except re.error as exc:
logger.warning(
"Invalid regex in hook.matcher %r for tool %r: %s",
hook.matcher,
tool_name,
exc,
)
# Treat invalid matcher as non-matching so the hook is effectively skipped.
return False

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Hooks

2 participants