Custom condition

Warn on edits that exceed a line-count threshold using a project-specific predicate.

The built-in conditions (Tool, FilePath, Content, SourceEdits, …) cover the common cases, but you’ll eventually want a predicate that depends on something specific to your project: a line-count threshold, a project-specific file shape, or a computed property of the event. Any frozen dataclass implementing check(self, evt: BaseHookEvent) -> bool satisfies the CustomCondition protocol and slots into only_if= / skip_if= alongside built-in conditions.

"""Warn on edits larger than a line-count threshold via a custom condition."""

from __future__ import annotations

from dataclasses import dataclass

from captain_hook import (
    Allow,
    BaseHookEvent,
    CustomCondition,
    Event,
    Input,
    Warn,
    nudge,
)


@dataclass(frozen=True)
class LargeEdit(CustomCondition):
    max_lines: int = 50

    def check(self, evt: BaseHookEvent) -> bool:
        return evt.content is not None and evt.content.count("\n") > self.max_lines


nudge(
    "Large edit detected — consider splitting into smaller changes.",
    only_if=[LargeEdit(max_lines=10)],
    events=Event.PreToolUse,
    tests={
        Input(tool="Edit", content="\n".join(str(i) for i in range(20))): Warn(),
        Input(tool="Edit", content="one\ntwo\n"): Allow(),
    },
)

What it catches

Input(tool="Edit", content="\n".join(str(i) for i in range(20)))  # 20-line edit clears the 10-line threshold

What it allows

Input(tool="Edit", content="one\ntwo\n")  # small edit stays under the threshold

The catch / allow split mirrors the hook inline tests, so it stays true as the hook evolves.

Run it yourself

uvx capt-hook --hooks docs/examples test

See also