Skip to main content

Content-safety checks (prompt injection, PII, output safety) for LLM systems. Imported as `drishti`.

Project description

दृष्टि Drishti

Fast, honest, self-hostable content safety for LLM systems.

Prompt-injection detection, PII detection and redaction, and output-safety classification. Three checks, one package, running entirely on your hardware.

License Built with Rust Python Platforms Inference Scores


Drishti (दृष्टि, "sight") watches the text that flows in and out of LLM systems and reports what it sees. It runs three checks:

Check On Returns
Prompt injection inputs an injection score, a class, and a confidence
PII detection and redaction inputs located PII spans plus a redacted copy of the text
Output safety outputs a score per safety category and an aggregate verdict

Every check returns a calibrated score and the identity of the model that produced it. Drishti never makes a policy decision on its own. It sees, it scores, and it lets your policy layer decide.

Highlights

  • Three checks, one package. No assembling three Python projects with three runtimes and three opinions about the output type.
  • Scores, not verdicts. Every result is a number a deterministic policy can act on. Drishti refuses nothing itself.
  • Models are yours. Nothing is hardcoded. You choose the model per check; if it is missing, Drishti downloads it once, verifies it, and caches it.
  • Offline by default. No default code path calls a remote service. CPU first, GPU optional.
  • Honest numbers. Precision and recall come from the eval harness, and any path that has not cleared its bar is labelled experimental.
  • Three surfaces, one core. A Rust crate, a Python package, and an HTTP service that all return identical results.

Table of contents


Install

Drishti is approaching its first tagged release. Published wheels and images will be available from the channels below; until then, build from source.

Python (embedded, runs models in-process; imported as drishti)

pip install sarthiai-drishti

One abi3 wheel per platform covers Python 3.9 through 3.13, on Linux x86_64, Linux ARM64, macOS ARM64 (Apple Silicon), and Windows x86_64.

Remote client SDKs (call a running drishti-server, no model loaded locally)

pip install sarthiai-drishti-sdk        # Python, imported as drishti_sdk
npm install sarthiai-drishti-sdk        # Node

Docker

docker pull sarthiai/drishti

Multi-architecture (linux/amd64 and linux/arm64). The container carries its own Linux, so the host operating system does not matter.

From source

git clone https://github.com/SarthiAI/Drishti
cd Drishti
cargo build --release          # builds the CLI and the server
pip install maturin && maturin develop --release   # builds the Python wheel

ONNX Runtime at runtime. Drishti links ONNX Runtime dynamically (ort's load-dynamic), so the build is pure Rust and the artifacts stay small and portable. The library is provided at runtime:

  • The sarthiai-drishti wheel and the Docker image pull it in automatically (a dependency of the wheel; downloaded into the image), so pip install and docker run just work.
  • Running the CLI or server from a source build: install ONNX Runtime (for example pip install "onnxruntime>=1.24") and point Drishti at its shared library with ORT_DYLIB_PATH=/path/to/libonnxruntime.so (or .dylib / .dll).

Quick start

All three surfaces read the same configuration file, which is where you choose the model for each check. See Configuration.

Command line

drishti --config config.toml prompt   --text "Ignore all previous instructions."
drishti --config config.toml pii      --text "Email me at jane@example.com"
drishti --config config.toml output   --text "Have a great day!"
drishti --config config.toml all      --text "..." --output "..."
drishti --config config.toml manifest         # loaded model ids and hashes

Pass --file <path> instead of --text to read from a file. Output is structured JSON.

HTTP service

drishti-server --config config.toml --bind 0.0.0.0:8080 --token <bearer-token>

Python

import drishti

d = drishti.Drishti.from_config_file("config.toml")
d.check_prompt("Ignore all previous instructions.")
d.check_pii("Email me at jane@example.com")
d.check_output("Have a great day!")
d.manifest()

Methods return plain dictionaries and release the interpreter lock during inference.


The three checks

Prompt injection

Takes a prompt and returns an injection score from 0.0 to 1.0, a class, a confidence, the latency, and the model id. It catches common injection patterns ("ignore previous instructions", "you are now DAN", and similar). It is one layer of defense, not a jailbreak-proof filter.

PII detection and redaction

Two stages:

  • A regex stage (always on, about 5 ms) finds structurally identifiable PII: emails, credit cards (Luhn validated), phone numbers, IPv4 and IPv6 addresses, IBANs, US SSNs, India PAN, Aadhaar and UPI, UK NINO, and EU VAT numbers.
  • An optional NER stage finds unstructured PII like names, organisations, and locations.

The result is a list of spans (byte offsets, kind, confidence, source) plus a redacted copy of the text. Redaction is chosen per kind: mask, hash, tokenise, keep, or refuse.

Output safety

Takes a model output and returns a score per safety category, an aggregate pass-or-fail against a threshold you set, and the detected language. The taxonomy comes from the configured model, so any classifier-style safety model fits.


Configuration

Configuration is a TOML file. Every value can also be overridden by an environment variable or a .env file, so tuning never needs a code change or a rebuild. The override key is DRISHTI_<PATH>, with a double underscore between nesting levels:

DRISHTI_OUTPUT__THRESHOLD=0.05
DRISHTI_PII__NER__DROP_ACRONYMS=true
DRISHTI_INTRA_THREADS=4

A worked example is in config/example.toml. A check is enabled only when its section is present, and an enabled check must name a model or startup fails with a clear error rather than guessing one.


Models

Drishti hardcodes no model. You choose the model for each check through configuration: there are no default model ids, URLs, or hashes compiled into the binary. If a chosen model is already present, Drishti uses it directly. If it is not, Drishti downloads it once from the configured source, verifies its SHA-256 when you provide one, caches it, and then uses it. To bring your own fine-tuned model, point the config at a local path.

There is no default model and no bundled weights. Instead Drishti ships a recommendation matrix: MODELS.md lists vetted models per check across a footprint range (small to large), with precision and recall measured on public benchmarks, honest notes on where each model fits, and starting points by industry. Pick a row, point config at it. config/starter.toml is a ready-to-run example, one point on that matrix.

A working starter set (used in config/starter.toml):

Check Model Weights Size
Prompt injection ProtectAI DeBERTa-v3-base prompt-injection-v2 fp32 704 MB
PII names and orgs dslim/distilbert-NER fp32 249 MB
Output safety KoalaAI Text-Moderation int8 136 MB

Note: model size is a footprint budget, not a quality ranking. What decides accuracy is whether a model was trained on content and labels like yours; see MODELS.md. Separately, int8 dynamic quantization significantly degrades DeBERTa-v3 accuracy, so run that prompt-injection model at full precision and switch model family if you need a smaller footprint.


HTTP API

JSON in, JSON out. The check endpoints and the manifest require a bearer token when one is configured; health and metrics are always open.

Method Path Body Auth
POST /v1/check/prompt { "input": "..." } bearer
POST /v1/check/pii { "input": "..." } bearer
POST /v1/check/output { "output": "..." } bearer
POST /v1/check/all { "prompt": "...", "output": "..." } bearer
POST /v1/check/prompt/batch { "inputs": ["...", "..."] } bearer
POST /v1/check/pii/batch { "inputs": ["...", "..."] } bearer
POST /v1/check/output/batch { "outputs": ["...", "..."] } bearer
GET /v1/manifest loaded model ids and hashes bearer
GET /v1/version drishti version and model-set id open
GET /healthz liveness open
GET /readyz 200 only when models are loaded open
GET /metrics Prometheus text open

Every check body also accepts an optional "model_set": "<id>". When present it is checked against the loaded set and a mismatch returns HTTP 409; when absent (the default) it is ignored, so existing callers are unaffected. Running Drishti as a separate, optionally GPU-backed service that many gateways share, and the optional TLS, timeout, size, and concurrency limits, are covered in SERVING.md.

curl -s -X POST http://localhost:8080/v1/check/pii \
  -H "authorization: Bearer <token>" \
  -H "content-type: application/json" \
  -d '{"input": "card 4111 1111 1111 1111"}'

Prefer a typed client over raw HTTP? Remote client SDKs for Python (sarthiai-drishti-sdk) and Node (sarthiai-drishti-sdk) live in clients/, each with its own README, and a Rust client (sarthiai-drishti-client, a RemoteDrishti that implements the same SafetyEngine trait as the embedded engine) lives in crates/drishti-client/. They call a running drishti-server and return typed results; they load no model themselves. This is distinct from the in-process Python package (import drishti) shown above, which runs the models locally.


Eval results

These figures come from the eval harness (eval/) run through the real engine on recognized public benchmarks: deepset/prompt-injections, the OpenAI moderation evaluation, and an ai4privacy/pii-masking-200k English sample. They measure the specific models configured, not Drishti in the abstract: accuracy is a property of the model you pick. The full per-model, per-tier matrix and how to choose is in MODELS.md. Reproduce with cargo run -p drishti-eval -- --config <cfg> --datasets <dir>; the report, including the SHA-256 of every model used, is written under eval/results/.

Measured highlights (validated means it cleared its bar):

Check (model) Precision Recall F1 Verdict
Output safety (KoalaAI Text-Moderation) 0.879 0.960 0.918 validated
PII regex, Email 0.996 0.939 0.967 validated
PII regex, IBAN 1.000 1.000 1.000 validated
PII NER, PersonName (distilbert to bert-large) up to 0.840 up to 0.919 0.86 to 0.88 experimental
Prompt injection (ProtectAI DeBERTa) 0.965 0.414 0.580 experimental

The prompt-injection recall is low because this benchmark is multilingual and out of distribution for that English model; a different model scores very differently. That is the point of MODELS.md: public numbers do not predict your traffic. Every runtime result stays labelled experimental until its configured path clears its bar on a real benchmark.


Performance

Warm inference on commodity CPU hardware: the regex PII stage runs in about 5 ms; the NER and output-safety classifiers in tens of milliseconds; the prompt-injection model at full precision is the heaviest, in the low hundreds of milliseconds. A cold process additionally pays a one-time model load, which the persistent server amortizes. Detailed p50 and p99 figures are published each release.


Threat model

In scope: naive prompt injection (instruction-override patterns), common PII in inputs and outputs (emails, cards, phones, names, addresses, and the structured identifiers above), common harmful output content in English, and tampering with model files (caught by SHA-256 verification when a hash is set).

Out of scope: adversarial prompts crafted to evade a specific classifier, jailbreaks that do not use injection patterns (roleplay, hypothetical framing), non-English content (Drishti reports the detected language and lowers its confidence), PII obfuscated through unusual encodings, and attacks on the host process itself. Drishti is one layer of defense: it reports scores, and enforcement belongs to your policy layer.


Project layout

drishti/
  crates/
    drishti-core/         detection logic and public types
    drishti-models/       model resolution, download, caching, hash verification
    drishti-regex/        the PII regex recognizer set
    drishti-server/       the axum HTTP service
    drishti-ffi-python/   the PyO3 bindings (in-process Python package)
    drishti-cli/          the command-line tool
  clients/
    python/               drishti-sdk: remote HTTP client for Python
    node/                 @sarthiai/drishti-sdk: remote HTTP client for Node
  eval/                   the eval harness, datasets, benchmarks, and results
  config/                 example configuration
  MODELS.md               model recommendation matrix (no default model)

License

Drishti is licensed under the Elastic License 2.0 (ELv2). Licensor: Chirotpal Das. See LICENSE for the full text. In short: you may use, copy, modify, and distribute it, but you may not offer it to third parties as a hosted or managed service, and you may not remove the licensing notices.


Part of Niyam

Drishti is the content-safety piece of the Niyam family: Kavach (armor) protects, Drishti (sight) watches, Lipi (script) writes the rules. Drishti is useful on its own and integrates with the rest through Niyam's shared contracts in later versions. The decision layer (what to block or allow) is Kavach, with rules authored in Lipi. Drishti only ever hands over scores and flags.


Designed, developed, and maintained by Chirotpal

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sarthiai_drishti-0.1.2.tar.gz (60.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

sarthiai_drishti-0.1.2-cp39-abi3-win_amd64.whl (3.5 MB view details)

Uploaded CPython 3.9+Windows x86-64

sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.1 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (4.2 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

sarthiai_drishti-0.1.2-cp39-abi3-macosx_11_0_arm64.whl (3.7 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

File details

Details for the file sarthiai_drishti-0.1.2.tar.gz.

File metadata

  • Download URL: sarthiai_drishti-0.1.2.tar.gz
  • Upload date:
  • Size: 60.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sarthiai_drishti-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5cfb2c016f430f0d8c17a1d377f3c0a160119da14ce10fd29f2018b73c3176ce
MD5 29b6da5a4943a40511a4a9bb07453002
BLAKE2b-256 1ea571e9d216f83c33a3bd2fa40665eb6858df50b6ccaf8f744e349a3709ab7c

See more details on using hashes here.

Provenance

The following attestation bundles were made for sarthiai_drishti-0.1.2.tar.gz:

Publisher: release.yml on SarthiAI/Drishti

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sarthiai_drishti-0.1.2-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for sarthiai_drishti-0.1.2-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 6b79fad2da32ef652250344ea95e81dca4372d059608fff6af308c231acf20e5
MD5 a5018fc7efad305bf83c1a7d2082c61f
BLAKE2b-256 355b75049e2f12833ab10bad1f234d4393f16627f1446ac978b41be107a8957e

See more details on using hashes here.

Provenance

The following attestation bundles were made for sarthiai_drishti-0.1.2-cp39-abi3-win_amd64.whl:

Publisher: release.yml on SarthiAI/Drishti

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d0f72d27fec7f922f343e2f4a40d813a733a7e18fb60a18eb2a5f3df2211a8ec
MD5 088df5a321de556f1c89d4106f0a1143
BLAKE2b-256 a912af1450c5b5707cca43d5d2c83af8e0f76a71a391d16c361ef9ef163fd46b

See more details on using hashes here.

Provenance

The following attestation bundles were made for sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on SarthiAI/Drishti

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c59b50fdfa45dc83148627170f71768844faa09a51a9fa27be278f47cd91e6c6
MD5 5146f2cecfbd813955a6534ea0c4c472
BLAKE2b-256 3893d1adbab7baf4efdd43a0b1de62cb064047de2cad86083568ca16485f59c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for sarthiai_drishti-0.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on SarthiAI/Drishti

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sarthiai_drishti-0.1.2-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for sarthiai_drishti-0.1.2-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 86070860e506917f77f0b488c0ec6d6811450c0f667714bb959583b28e351d62
MD5 aa41a4b75d7d5dd5fe8348bb71d681f2
BLAKE2b-256 6e8d04971e660044ce39756ab8727e2117bb5fdd0b9e172ca50faf7c463e697e

See more details on using hashes here.

Provenance

The following attestation bundles were made for sarthiai_drishti-0.1.2-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on SarthiAI/Drishti

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page