潜龙 — a passive, semantic anomaly-detection sentinel for system events and logs.
Project description
trace-sentinel
Passive anomaly detection for logs and system events.
trace-sentinel learns a baseline from your event stream and surfaces only what
genuinely deviates from it — both statistically (online z-score / MAD) and
semantically (log lines whose content is new, not just whose numbers are
large). It's a zero-dependency Python library and CLI, with an optional live
dashboard.
It is a building block, not a platform: embed it in an app, a job runner, or a pipeline, and route the anomalies wherever you already send alerts.
Features
- Streaming and passive — feed events one at a time; baselines update in O(1) with no batch jobs and no stored history.
- Statistical + semantic — z-score/EWMA and robust median/MAD for magnitudes, plus a semantic-novelty detector for unfamiliar content — both expressed in the same sigma units, so one threshold governs everything.
- Calm by default — a 3σ default, outlier-resistant detectors, and baseline seeding so it isn't noisy from a cold start.
- Zero dependencies — pure standard-library core, Python 3.9+. Optional extras only if you bring real vector embeddings.
- Composable — write your own extractors, swap detectors, and send anomalies to any sink (console, JSON lines, webhook, your SIEM).
- Batteries included — a
trace-sentinelCLI and atrace-sentinel-hudlive dashboard.
Install
pip install trace-sentinel
# optional extras
pip install "trace-sentinel[embeddings]" # numpy, for custom vector embeddings
pip install "trace-sentinel[dev]" # pytest, ruff, mypy
Python 3.9+. The core has no third-party dependencies.
Quickstart
from trace_sentinel import Sentinel, Event
sentinel = Sentinel(threshold=3.0, warmup=30, enable_semantic=True)
for line in open("app.log"):
for anomaly in sentinel.observe(Event.from_line(line, source="app")):
print(anomaly.severity.value, anomaly.explanation)
observe() returns the anomalies for that event (usually none). Nothing fires
during warmup or for values inside the learned baseline.
CLI
trace-sentinel watch app.log --semantic # plain text log
trace-sentinel watch events.jsonl --jsonl --format json # JSON lines -> JSON out
trace-sentinel watch /var/log/auth.log --follow --semantic # tail -f a live file
trace-sentinel watch app.log --semantic --seed 3000 # prime baselines first
Live dashboard
trace-sentinel-hud # streams your real system logs to http://localhost:8787
A self-contained HUD (threat gauge, σ-timeline, per-metric rings, scrolling anomaly feed) driven entirely by real engine state — no simulated data.
How it works
┌───────────┐ features ┌────────────┐ sigma ┌──────────┐
Event ───────▶ │ Extractors│ ────────────▶ │ Detectors │ ────────▶ │ Sentinel │ ──▶ Anomaly
(log line) └───────────┘ message.length└────────────┘ z / MAD │ threshold│ (+ Sink)
│ message.tokens └──────────┘
│ ... ▲
└────────── message text ───▶ Semantic novelty ──────┘
- Extractors turn each
Eventinto named numeric metrics (message.length,message.tokens, numeric fields, inter-arrival time, …). - Detectors keep one online baseline per metric and return a standardized deviation in sigma. A value is scored against history before it's folded in, so a spike is measured against the past, not against itself.
- The Sentinel emits an
Anomalywhen|score| ≥ threshold, after a per-metric warmup. - The semantic layer embeds the message text, tracks a decaying centroid of "normal," and scores novelty — standardized to sigma so it thresholds exactly like the numeric metrics.
Cold baselines over-alert, so Sentinel.prime() (and the bundled benign-signal
corpus in trace_sentinel.seed) can establish a stable "normal" up front. See
docs/concepts.md.
Roadmap
| Stage | Capability | Status |
|---|---|---|
| Detect | passive statistical + semantic detection (this release) | ✅ 0.1 |
| Correlate | cross-source correlation, alert routing, dashboards | planned |
| Respond | automated response / playbooks | planned |
Documentation
| Doc | Contents |
|---|---|
| Quickstart | Install and first run |
| Concepts | The detection model, sigma, and the 2σ caveat |
| Detectors | Z-score, EWMA drift, robust MAD |
| Semantic layer | Novelty scoring; plugging in real embeddings / LLMs |
| Extractors | Built-ins and writing your own |
| CLI | trace-sentinel watch reference |
| API reference | Public classes and functions |
| Production | Tuning, persistence, scaling, gotchas |
| FAQ | How it compares to SIEM/UEBA |
Development
pip install -e ".[dev]"
pytest # test suite
ruff check . # lint
mypy # type-check (strict)
License
MIT © 2026 Ken Li. See LICENSE.
Also published under the name 潜龙 (qiánlóng, “hidden dragon”) — dormant until something genuinely stirs it.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trace_sentinel-0.2.0.tar.gz.
File metadata
- Download URL: trace_sentinel-0.2.0.tar.gz
- Upload date:
- Size: 60.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d770353946c76f1538600bfd3eb13bfca7e53e55b47497b0163c9daba15f9a7e
|
|
| MD5 |
9daa6f32c65f7c410dbad8aaf227a93b
|
|
| BLAKE2b-256 |
748b10551dec14b1b27f83b5faa01585042cc375568ad2e9a2a704a559523276
|
File details
Details for the file trace_sentinel-0.2.0-py3-none-any.whl.
File metadata
- Download URL: trace_sentinel-0.2.0-py3-none-any.whl
- Upload date:
- Size: 43.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21f9dd7642f79638f1b988f91a8e8b13d756cb6e842d6bf0066961cb6fc138b5
|
|
| MD5 |
49d63bb54826edc7cd2514b6ea60ac4a
|
|
| BLAKE2b-256 |
cd733998a8b7c88b8d24ab5d452c65e7c887faf1badc181035cf0130f2d42c95
|