serena.hooks#


class HookClient(
value,
names=<not given>,
*values,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)[source]#

Bases: Enum

The 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 OutputData(
permission_decision: Literal['deny', 'allow'],
permission_decision_reason: str,
additional_context: str = '',
)[source]#

Bases: object

Parameters:
  • permission_decision (Literal['deny', 'allow'])

  • permission_decision_reason (str)

  • additional_context (str)

class PreToolUseRemindAboutSymbolicToolsHook(client)[source]#

Bases: PreToolUseHook

Pre-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,
)[source]#

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. Returns False while we are still within _MIN_DENY_INTERVAL_SECONDS of the most recent emitted deny — in that case the entire hook is short-circuited (no counter updates, no deny). Returns True when no deny has been emitted yet in this session, or when the window has elapsed.

Parameters:

now (datetime)

Return type:

bool

is_read_file_call()[source]#
Returns:

whether the tool call reads a file-like target.

Return type:

bool

is_read_code_file_call()[source]#
Returns:

whether the tool call reads a source-like file target.

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: PreToolUseHook

Pre-tool-use hook that auto-approves Serena tool calls while the client is in a permissive permission mode.

Claude Code’s permissive permission modes (acceptEdits for blanket edit approval and auto for 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_body or rename_symbol) would still prompt the user on every call. This hook emits an allow decision 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.

bypassPermissions and dontAsk are deliberately excluded. bypassPermissions already approves everything before the hook would matter, so silence here is harmless. dontAsk is 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