serena.hooks#
Source code: serena/hooks.py
- class HookClient(
- value,
- names=<not given>,
- *values,
- module=None,
- qualname=None,
- type=None,
- start=1,
- boundary=None,
Bases:
EnumThe client application that triggered the hook.
- class Hook(client)[source]#
Bases:
ABC- Parameters:
client (HookClient)
- class PreToolUseHook(client)[source]#
Bases:
Hook,ABC- Parameters:
client (HookClient)
- class PreToolUseRemindAboutSymbolicToolsHook(client)[source]#
Bases:
PreToolUseHookPre-tool-use hook that nudges the agent toward Serena’s symbolic tools.
Tracks consecutive uses of grep and read-file tools via a persisted
ToolUseCounter. When the number of recent calls reaches the configured threshold, a deny response is emitted with a reminder to use symbolic alternatives.The counter for a given tool type is reset whenever
a Serena tool is invoked (both counters are reset),
a deny is emitted (the acting counter is reset so the next retry starts fresh),
or the configured reset period elapses between two consecutive calls of that same tool type — i.e. the period gates the gap between successive calls, not an absolute sliding window. Three grep calls at t=0, t=9, t=18 therefore count as a burst of three, even though the total span (18s) exceeds the 10s grep period; only an individual pair that is more than 10s apart resets the counter.
Non-tracked tools (Edit, Write, Bash, etc.) are deliberately neutral: they neither increment nor reset counters, so they also do not mask bursts by pushing the last timestamp forward.
The hook is additionally gated by
ToolUseCounter._MIN_DENY_INTERVAL_SECONDS(two minutes by default): once a deny has been emitted, every subsequent invocation of this hook is a no-op until the window has elapsed — neither the counters are updated nor any further deny is produced. This prevents the agent from being nudged more than once per window during a sustained non-symbolic-tool burst, and also avoids surprising the user with reminders that were already counted up under stale state.- Parameters:
client (HookClient)
- class ToolUseCounter(
- n_recent_read_file_uses: int = 0,
- n_recent_grep_uses: int = 0,
- n_recent_non_symbolic_uses: int = 0,
- last_grep_use_timestamp: datetime.datetime | None = None,
- last_read_file_use_timestamp: datetime.datetime | None = None,
- last_non_symbolic_use_timestamp: datetime.datetime | None = None,
- last_deny_timestamp: datetime.datetime | None = None,
Bases:
object- Parameters:
n_recent_read_file_uses (int)
n_recent_grep_uses (int)
n_recent_non_symbolic_uses (int)
last_grep_use_timestamp (datetime | None)
last_read_file_use_timestamp (datetime | None)
last_non_symbolic_use_timestamp (datetime | None)
last_deny_timestamp (datetime | None)
- is_hook_active(now)[source]#
- Returns:
whether the hook should engage at all at
now. ReturnsFalsewhile we are still within_MIN_DENY_INTERVAL_SECONDSof the most recent emitted deny — in that case the entire hook is short-circuited (no counter updates, no deny). ReturnsTruewhen no deny has been emitted yet in this session, or when the window has elapsed.- Parameters:
now (datetime)
- Return type:
bool
- class SessionStartActivateProjectHook(client)[source]#
Bases:
Hook- Parameters:
client (HookClient)
- class SessionEndCleanupHook(client)[source]#
Bases:
Hook- Parameters:
client (HookClient)
- class PreToolUseAutoApproveSerenaHook(client)[source]#
Bases:
PreToolUseHookPre-tool-use hook that auto-approves Serena tool calls while the client is in a permissive permission mode.
Claude Code’s permissive permission modes (
acceptEditsfor blanket edit approval andautofor hands-off autonomous execution) only apply to its built-in editing tools or its auto-mode classifier; Serena’s destructive tools (e.g.replace_symbol_bodyorrename_symbol) would still prompt the user on every call. This hook emits anallowdecision for any Serena MCP tool call whenever the client reports one of these modes as the active permission mode, so blanket approvals also cover Serena’s tools. In all other situations it stays silent, preserving the default approval flow.bypassPermissionsanddontAskare deliberately excluded.bypassPermissionsalready approves everything before the hook would matter, so silence here is harmless.dontAskis the user’s deliberate deny-by-default posture (auto-deny unless an explicit allow rule matches); the hook honors that choice and stays silent rather than blanket overriding it.- Parameters:
client (HookClient)
- class HookCommands[source]#
Bases:
AutoRegisteringGroup