-
Notifications
You must be signed in to change notification settings - Fork 0
Writing Custom Detectors
Jacob Centner edited this page Apr 10, 2026
·
1 revision
Sentinel supports third-party detectors via Python's entry-points plugin system. Install a detector package with pip install, and Sentinel auto-discovers it.
Every detector extends the Detector base class:
from sentinel.detectors.base import Detector
from sentinel.models import (
DetectorContext, DetectorTier, Evidence, EvidenceType, Finding, Severity,
)
class MyDetector(Detector):
@property
def name(self) -> str:
return "my-detector"
@property
def description(self) -> str:
return "Short description of what this detector finds"
@property
def tier(self) -> DetectorTier:
return DetectorTier.DETERMINISTIC # or HEURISTIC, LLM_ASSISTED
@property
def categories(self) -> list[str]:
return ["code-quality"]
def detect(self, context: DetectorContext) -> list[Finding]:
findings = []
# Your detection logic here
# Use context.repo_root, context.scope, context.changed_files, etc.
findings.append(Finding(
detector=self.name,
category="code-quality",
severity=Severity.MEDIUM,
confidence=0.85,
title="Issue found in example.py",
description="Detailed description of the issue",
evidence=[
Evidence(
type=EvidenceType.CODE,
content="The problematic code snippet",
source="src/example.py",
line_range=(10, 20),
),
],
file_path="src/example.py",
line_start=10,
))
return findingsThe context object provides:
| Field | Type | Description |
|---|---|---|
repo_root |
str |
Absolute path to the repository root |
scope |
ScopeType |
FULL, INCREMENTAL, or TARGETED
|
changed_files |
list[str] |
Files changed since last run (incremental) |
target_paths |
list[str] |
Specific paths to scan (targeted) |
config |
dict |
Runtime config including provider, skip_llm, num_ctx, model_capability
|
conn |
Connection |
SQLite connection (optional) |
run_id |
int |
Current run ID (optional) |
In your package's pyproject.toml:
[project.entry-points."sentinel.detectors"]
my-detector = "my_package.detector:MyDetector"After pip install my-package, Sentinel will auto-discover and register your detector.
If your detector uses an LLM, set the capability tier:
from sentinel.models import CapabilityTier
class MyLLMDetector(Detector):
@property
def tier(self) -> DetectorTier:
return DetectorTier.LLM_ASSISTED
@property
def capability_tier(self) -> CapabilityTier:
return CapabilityTier.BASIC
def detect(self, context: DetectorContext) -> list[Finding]:
if context.config.get("skip_llm"):
return []
provider = context.config.get("provider")
if provider is None or not provider.check_health():
return []
# Use provider.generate(prompt, ...) for LLM calls
response = provider.generate("Analyze this code: ...")
# Parse response and create findingsFor detectors that don't need packaging, use detectors_dir in config:
[sentinel]
detectors_dir = "my-detectors/"Sentinel loads all .py files from this directory and registers any Detector subclasses found.
- Set confidence realistically (0.0–1.0) — deterministic checks can be 1.0, heuristic ~0.8, LLM ~0.6
- Include evidence with every finding — cite the specific code, config, or history
- Respect
context.scope— for incremental scans, only checkchanged_files - Handle errors gracefully — the runner catches exceptions per-detector, but clean error handling is better
- Skip files in
COMMON_SKIP_DIRS(available fromsentinel.detectors.base)
Local Repo Sentinel · MIT License
Getting Started
Reference
Detectors
- Detector: Todo Scanner
- Detector: Complexity
- Detector: Dead Code
- Detector: Dep Audit
- Detector: Docs Drift
- Detector: Unused Deps
- Detector: Lint Runner
- Detector: ESLint Runner
- Detector: Go Linter
- Detector: Rust Clippy
- Detector: Git Hotspots
- Detector: Stale Env
- Detector: Semantic Drift
- Detector: Test Coherence
- Detector: CI/CD Drift
- Detector: Architecture Drift
- Detector: Inline Comment Drift
- Detector: Intent Comparison
Advanced
Workflow