hooks

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ActionAllow    = "allow"
	ActionDeny     = "deny"
	ActionModify   = "modify"
	ActionInstruct = "instruct"
)

DecisionAction constants for HookDecision.Action.

View Source
const (
	SessionStart    = "session.start"
	SessionEnd      = "session.end"
	TurnStart       = "turn.start"
	TurnEnd         = "turn.end"
	ToolCallStart   = "tool_call.start"
	ToolCallEnd     = "tool_call.end"
	ToolCallError   = "tool_call.error"
	FileRead        = "file.read"
	FileWrite       = "file.write"
	FileEdit        = "file.edit"
	FileDelete      = "file.delete"
	CompactionStart = "compaction.start"
	CompactionEnd   = "compaction.end"
	BudgetWarning   = "budget.warning"
	BudgetExceeded  = "budget.exceeded"
	ErrorOccurred   = "error.occurred"
	ErrorRecovered  = "error.recovered"
	ModelSwitch     = "model.switch"
	ProviderSwitch  = "provider.switch"
	UserInput       = "user.input"
	AgentResponse   = "agent.response"

	// Review lifecycle events
	ReviewQueued    = "review.queued"
	ReviewStarted   = "review.started"
	ReviewCompleted = "review.completed"
	ReviewFailed    = "review.failed"
	ReviewFixed     = "review.fixed"
)

LifecycleEventType constants representing agent lifecycle events.

Variables

This section is empty.

Functions

func Execute

func Execute(ctx context.Context, event EventType, data map[string]interface{}) error

Execute runs all hooks for an event on the global registry.

func ExecuteAsync

func ExecuteAsync(ctx context.Context, event EventType, data map[string]interface{})

ExecuteAsync runs hooks asynchronously on the global registry.

func ExecuteAsyncEnvelope

func ExecuteAsyncEnvelope(ctx context.Context, env EventEnvelope)

ExecuteAsyncEnvelope runs hooks asynchronously on the global registry using a typed envelope.

func ExecuteEnvelope

func ExecuteEnvelope(ctx context.Context, env EventEnvelope) error

ExecuteEnvelope runs all hooks for an event on the global registry using a typed envelope.

func FormatEvent

func FormatEvent(event Event) string

FormatEvent returns a human-readable log line for the event.

func LoadConventionPolicies

func LoadConventionPolicies(cwd string) int

LoadConventionPolicies discovers and loads convention policy files. Convention: auto-discovered *policy*.{md,go} files from:

  • {cwd}/.agents/policies/ (project scope)
  • Hawk user state policies directory

Returns the number of policies loaded.

func LoadHooksDir

func LoadHooksDir(dir string) error

LoadHooksDir loads hooks from a directory.

func Register

func Register(h Hook)

Register adds a hook to the global registry.

func RegisterDecisionHook

func RegisterDecisionHook(fn DecisionHookFn)

RegisterDecisionHook adds a decision hook to the global list.

func RegisterDecisionHookWithConfig

func RegisterDecisionHookWithConfig(config DecisionHookConfig, fn DecisionHookFn)

RegisterDecisionHookWithConfig adds a decision hook with matching and priority.

func ResetDecisionHooks

func ResetDecisionHooks()

ResetDecisionHooks clears all registered decision hooks. Intended for testing.

Types

type DecisionHookConfig

type DecisionHookConfig struct {
	Name     string
	Matcher  DecisionMatcher
	Priority int // Lower = earlier evaluation
}

DecisionHookConfig configures a decision hook with matching and priority.

type DecisionHookFn

type DecisionHookFn func(event string, data map[string]interface{}) *HookDecision

DecisionHookFn is a function that inspects an event and optionally returns a decision. Returning nil means "no opinion" (proceed normally).

type DecisionMatcher

type DecisionMatcher struct {
	Events    []string // Event types to match (e.g., "pre_tool", "post_tool")
	ToolNames []string // Tool names to match (e.g., "Bash", "Write", "Edit")
}

DecisionMatcher specifies which events and tools a decision hook applies to. Empty arrays mean "match all".

func (*DecisionMatcher) Match

func (m *DecisionMatcher) Match(event string, toolName string) bool

Match returns true if the matcher applies to the given event and tool name.

type Diagnostic

type Diagnostic struct {
	Line     int
	Column   int
	Severity int // 1=error, 2=warning, 3=info, 4=hint
	Code     string
	Message  string
}

Diagnostic mirrors lsp.Diagnostic to avoid import cycle.

type EnvelopeFn

type EnvelopeFn func(ctx context.Context, envelope EventEnvelope) error

EnvelopeFn is the typed hook function signature using EventEnvelope.

func AdaptLegacyFn

func AdaptLegacyFn(fn func(ctx context.Context, data map[string]interface{}) error) EnvelopeFn

AdaptLegacyFn wraps a legacy hook function into an EnvelopeFn. The legacy function receives only the payload from the envelope.

type Event

type Event struct {
	Name      string
	Timestamp time.Time
	Data      map[string]interface{}
	Source    string
}

Event represents a single lifecycle event emitted by the agent.

type EventBus

type EventBus struct {
	Hooks      map[string][]*LifecycleHook
	Listeners  map[string][]chan Event
	History    []Event
	MaxHistory int
	// contains filtered or unexported fields
}

EventBus is the central publish/subscribe mechanism for lifecycle events.

func NewEventBus

func NewEventBus() *EventBus

NewEventBus creates a new EventBus with sensible defaults.

func (*EventBus) Emit

func (eb *EventBus) Emit(event Event)

Emit fires all hooks for the event type and sends to listeners. Synchronous hooks run in priority order; async hooks run in goroutines.

func (*EventBus) GetHistory

func (eb *EventBus) GetHistory(eventType string, limit int) []Event

GetHistory returns the most recent events of the given type, limited to `limit`. If eventType is empty, all events are considered.

func (*EventBus) OnError

func (eb *EventBus) OnError(fn func(err error))

OnError registers a convenience hook that fires on ErrorOccurred events.

func (*EventBus) OnFileWrite

func (eb *EventBus) OnFileWrite(fn func(path string))

OnFileWrite registers a convenience hook that fires on FileWrite events.

func (*EventBus) OnSessionEnd

func (eb *EventBus) OnSessionEnd(fn func(duration time.Duration, tokens int))

OnSessionEnd registers a convenience hook that fires when a session ends.

func (*EventBus) OnToolCall

func (eb *EventBus) OnToolCall(fn func(tool string, duration time.Duration))

OnToolCall registers a convenience hook that fires when a tool call completes.

func (*EventBus) Register

func (eb *EventBus) Register(hook *LifecycleHook)

Register adds a hook to the bus for its configured event type.

func (*EventBus) Stats

func (eb *EventBus) Stats() EventStats

Stats returns aggregate statistics about the event bus.

func (*EventBus) Subscribe

func (eb *EventBus) Subscribe(eventType string) <-chan Event

Subscribe returns a channel that receives events of the given type.

func (*EventBus) Unregister

func (eb *EventBus) Unregister(hookID string)

Unregister removes a hook by its ID from all event types.

func (*EventBus) Unsubscribe

func (eb *EventBus) Unsubscribe(eventType string, ch <-chan Event)

Unsubscribe removes a previously subscribed channel.

type EventEnvelope

type EventEnvelope struct {
	Timestamp     time.Time              `json:"timestamp"`
	Source        string                 `json:"source"`         // e.g. "hooks", "mission", "plugin"
	SessionID     string                 `json:"session_id"`     // session that triggered the event
	AgentID       string                 `json:"agent_id"`       // agent that triggered the event
	CorrelationID string                 `json:"correlation_id"` // traces across hook chains
	EventType     EventType              `json:"event_type"`
	Payload       map[string]interface{} `json:"payload"` // event-specific data
}

EventEnvelope provides structured, typed metadata for hook events. It wraps the raw payload with tracing and context fields.

type EventStats

type EventStats struct {
	TotalEvents int
	ByType      map[string]int
	HookCount   int
	AsyncHooks  int
	AvgHookTime time.Duration
}

EventStats provides aggregate statistics about the event bus.

type EventType

type EventType string

EventType represents a hook event.

const (
	EventPreQuery      EventType = "pre_query"
	EventPostQuery     EventType = "post_query"
	EventPreTool       EventType = "pre_tool"
	EventPostTool      EventType = "post_tool"
	EventPreCompact    EventType = "pre_compact"
	EventPostCompact   EventType = "post_compact"
	EventFileChanged   EventType = "file_changed"
	EventSessionStart  EventType = "session_start"
	EventSessionEnd    EventType = "session_end"
	EventPermissionAsk EventType = "permission_ask"
	EventError         EventType = "error"
)

type Hook

type Hook struct {
	Name     string
	Event    EventType
	Priority int                                                          // lower = earlier
	Fn       func(ctx context.Context, data map[string]interface{}) error // legacy
	FnV2     EnvelopeFn                                                   // typed envelope (preferred)
}

Hook is a registered hook function.

func BuiltinHooks

func BuiltinHooks() []Hook

BuiltinHooks returns the default set of built-in hooks.

func LSPFeedbackHook

func LSPFeedbackHook(provider LSPFeedbackProvider) Hook

LSPFeedbackHook creates a hook that runs LSP diagnostics after file edits and provides blocking feedback when errors are found.

type HookDecision

type HookDecision struct {
	Action        string          `json:"action"` // "allow", "deny", "modify", "instruct"
	Reason        string          `json:"reason,omitempty"`
	Message       string          `json:"message,omitempty"` // User-facing message (for deny/instruct)
	ModifiedInput json.RawMessage `json:"modified_input,omitempty"`
}

HookDecision represents the outcome of a decision hook.

func Allow

func Allow() *HookDecision

Allow creates an allow decision.

func Deny

func Deny(reason string) *HookDecision

Deny creates a deny decision with a reason.

func ExecuteDecisionHooks

func ExecuteDecisionHooks(event string, data map[string]interface{}) *HookDecision

ExecuteDecisionHooks runs all registered decision hooks for the given event. It respects matchers (event type + tool name) and returns the first non-nil decision. If all hooks return nil, the result is nil (meaning no opinion, proceed normally). Fail-open: hook errors are logged but do not block the operation.

func ExecuteDecisionHooksSafe

func ExecuteDecisionHooksSafe(event string, data map[string]interface{}) *HookDecision

ExecuteDecisionHooksSafe runs all registered decision hooks with full fail-open semantics. Returns the first non-nil decision, or nil if all hooks return nil or panic.

func Instruct

func Instruct(message string) *HookDecision

Instruct creates an instruct decision that injects context without blocking. The agent receives the message as guidance for its next action.

func Modify

func Modify(reason string, modifiedInput json.RawMessage) *HookDecision

Modify creates a modify decision with modified input.

type LSPFeedbackProvider

type LSPFeedbackProvider interface {
	// DiagnosticsForFile returns diagnostics for a file path.
	// Returns nil if no LSP server is available for the file type.
	DiagnosticsForFile(ctx context.Context, filePath string) ([]Diagnostic, error)
}

LSPFeedbackProvider abstracts LSP diagnostics for the feedback hook. This interface allows the hook to call into the LSP manager without creating an import cycle.

type LifecycleHook

type LifecycleHook struct {
	ID       string
	Name     string
	Event    string
	Handler  func(Event) error
	Priority int
	Async    bool
	Enabled  bool
}

LifecycleHook is a registered handler for lifecycle events on the EventBus.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry stores and executes hooks.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a new hook registry.

func (*Registry) Execute

func (r *Registry) Execute(ctx context.Context, event EventType, data map[string]interface{}) error

Execute runs all hooks for an event. Fail-open: hook errors are logged but do not stop execution of subsequent hooks.

func (*Registry) ExecuteAsync

func (r *Registry) ExecuteAsync(_ context.Context, event EventType, data map[string]interface{})

ExecuteAsync runs hooks asynchronously (fire and forget). Uses a fresh context to avoid passing a cancelled caller context.

func (*Registry) ExecuteAsyncEnvelope

func (r *Registry) ExecuteAsyncEnvelope(_ context.Context, env EventEnvelope)

ExecuteAsyncEnvelope runs hooks asynchronously using a typed EventEnvelope.

func (*Registry) ExecuteEnvelope

func (r *Registry) ExecuteEnvelope(ctx context.Context, env EventEnvelope) error

ExecuteEnvelope runs all hooks for an event using a typed EventEnvelope. Hooks with FnV2 set receive the envelope directly; legacy Fn hooks receive the payload. Fail-open: hook errors are logged but do not stop execution of subsequent hooks.

func (*Registry) Register

func (r *Registry) Register(h Hook)

Register adds a hook to the registry.

type WrappedDecisionHook

type WrappedDecisionHook struct {
	Config DecisionHookConfig
	Fn     DecisionHookFn
}

WrappedDecisionHook pairs a config with its evaluation function.

Directories

Path Synopsis
Package audit provides waste-detection detectors for agent transcripts.
Package audit provides waste-detection detectors for agent transcripts.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL