Skip to main content

Behavioral integrity layer for AI systems during training and inference

Project description

signAI

Runtime behavioral integrity monitoring for PyTorch models.

signAI adds a small monitoring layer around training and inference so you can detect suspicious model behavior in real time — without exposing model weights, raw inputs, or gradients. The production layer supports:

  • Local artifact mode with no server
  • Daemon mode (localhost:7731, auto-discovered by the SDK)
  • Self-hosted server mode
  • Air-gapped private deployment mode

What signAI detects

signAI monitors a model's behavioral fingerprint rather than its accuracy. It catches anomalies such as:

  • distribution shift in inputs or activations
  • gradient manipulation and targeted poisoning during training
  • unexpected output distribution changes at inference time

Detection is based on a conditional behavioral model (CBM): for each operating state S, signAI learns the expected behavioral response Z and flags deviations.

What is in this repo

  • signai/core/: research and scoring core
  • signai/core/extractors/: S/Z feature extractors for classifiers, LLMs, and custom models
  • signai/core/detectors/: detector registry (Mahalanobis, neural, association)
  • signai/client/: production SDK
  • signai_server/: standalone REST server for hosted and self-hosted scoring

Install

SDK only, local mode:

pip install signai

SDK plus server dependencies:

pip install "signai[server]"

SDK plus server plus Postgres support:

pip install "signai[server,postgres]"

For local development in this repo:

python -m venv .venv
.venv\Scripts\activate
pip install -e ".[server]"

Quick Start

Local mode (any classifier)

from signai import monitor

m = monitor.attach(model, num_classes=10)
m.calibrate(clean_loader, device="cuda", phase="inference", calib_batches=200)
m.save("./integrity.json")

Load and score:

m = monitor.load(model, artifact="./integrity.json", device="cuda")

for x, y in test_loader:
    result = m.score_inference(x, y)
    if result.flagged:
        route_to_fallback(x)

LLM / large model quick start

For models above 200M parameters or HuggingFace generative models, use LLMExtractor and IntegrityMonitor directly:

from signai import IntegrityMonitor, LLMExtractor

extractor = LLMExtractor(llm)
m = IntegrityMonitor(llm, num_classes=None, extractor=extractor, detector_kind="v1")
m.calibrate_inference(clean_loader, calib_batches=200, device="cuda")
m.export_json("./integrity_llm.json")

Score LLM inference:

m = IntegrityMonitor(llm, num_classes=None, extractor=LLMExtractor(llm), detector_kind="v1")
m.import_json("./integrity_llm.json")

for batch in eval_loader:
    result = m.score_input(batch["input_ids"], None, device="cuda")

Remote mode

Start the server:

signai-server serve --host 0.0.0.0 --port 8000 --storage ./artifacts

Connect the SDK:

from signai import monitor

m = monitor.attach(
    model,
    num_classes=10,
    endpoint="http://localhost:8000",
    api_key="",
    monitor_id="demo-model",
    device="cuda",
)
m.calibrate(clean_loader, device="cuda", phase="inference", calib_batches=200)
m.save("./integrity.json")

Detector Kinds

signAI ships three detector algorithms. Choose by setting detector_kind:

Kind Algorithm Best for
"v1" Conditional Mahalanobis (sklearn) general purpose; fast; no GPU required
"nn" Neural conditional monitor complex activation geometry; higher accuracy
"assoc" Blockwise association neural monitor high-dimensional behavioral spaces

Use v1 as the default. Use nn or assoc when you need finer discrimination on complex models.

from signai import IntegrityMonitor, ClassificationExtractor

# Neural detector
m = IntegrityMonitor(
    model,
    num_classes=10,
    extractor=ClassificationExtractor(model),
    detector_kind="nn",
)

Extractor Kinds

signAI uses an extractor plugin system to support different model types. The right extractor is auto-selected when you use monitor.attach():

Extractor Auto-selected when Description
ClassificationExtractor ≤200M params, classification CNN/ViT classifier; tracks gradient geometry and activation depth
LLMExtractor >200M params or HF generative Per-module L2 norm delta tracking; constant memory

To override auto-selection:

from signai import IntegrityMonitor, LLMExtractor

# Force LLMExtractor on a model below the size threshold
m = IntegrityMonitor(model, extractor=LLMExtractor(model), detector_kind="v1")

To implement a custom extractor for a novel architecture:

from signai import SignatureExtractorBase
import numpy as np

class MyExtractor(SignatureExtractorBase):
    def prepare(self, example_batch): ...
    def reset_state(self): ...
    def extract_training(self, logits, loss) -> tuple[np.ndarray, np.ndarray]: ...
    def extract_inference(self, x, y, device="cpu", use_sensitivity=True) -> tuple[np.ndarray, np.ndarray]: ...

Deployment Modes

1. Local artifact

m = monitor.load(model, artifact="./integrity.json")

2. Daemon (localhost:7731)

The SDK auto-discovers a running signai-server on localhost:7731. No endpoint config needed:

m = monitor.attach(model, num_classes=10)  # connects to daemon if running

3. Self-hosted

m = monitor.load(
    model,
    endpoint="http://signai.internal:8000",
    api_key="...",
    monitor_id="my-model",
)

4. Air-gapped

m = monitor.load(
    model,
    endpoint="http://10.0.1.5:8000",
    api_key="...",
    monitor_id="my-model",
)

Training Loop Integration

First calibrate for the training phase — optimizer and criterion are required:

from signai import monitor
import torch

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
criterion = torch.nn.CrossEntropyLoss()

m = monitor.attach(model, num_classes=10)
m.calibrate(
    train_loader,
    device="cpu",
    phase="training",
    optimizer=optimizer,
    criterion=criterion,
)
m.save("./integrity_train.json")

Then score each training step after optimizer.step():

m = monitor.load(model, artifact="./integrity_train.json", device="cpu")

for x, y in train_loader:
    optimizer.zero_grad()
    logits = model(x)
    loss = criterion(logits, y)
    loss.backward()
    optimizer.step()

    result = m.score_training(logits, loss)
    if result.flagged:
        quarantine_update(result)

Inference Loop Integration

from signai import monitor

m = monitor.load(model, artifact="./integrity.json", device="cuda")

for x, y in test_loader:
    result = m.score_inference(x, y)
    if result.flagged:
        route_to_fallback(x)

Public API

Top-level exports from signai:

Symbol Description
monitor.attach(model, num_classes, ...) Create a new monitor
monitor.load(model, artifact, ...) Load from artifact or remote
Monitor Monitor class with calibrate, save, score_inference, score_training
MonitorResult Score result dataclass
IntegrityMonitor Advanced: unified monitor with extractor + detector_kind params
SignatureExtractorBase Advanced: ABC for custom extractor plugins
ClassificationExtractor Classifier extractor (CNN, ViT, HF classification)
LLMExtractor LLM extractor (generative transformers, >200M param models)

Run The Server

CLI

signai-server serve \
  --host 0.0.0.0 \
  --port 8000 \
  --storage ./artifacts \
  --store-backend file

Shortcut through the main CLI:

signai serve --host 0.0.0.0 --port 8000 --storage ./artifacts

Docker

docker build -t signai .
docker run -p 8000:8000 -v %cd%\artifacts:/data signai

docker-compose

docker compose up --build

Licensing

All usage requires a license key. A bundled trial key is active on fresh installs — no purchase needed to get started.

signai apply-key sk_...    # activate or renew a key
signai status              # show seat, plan, features, expiry, usage

Visit https://umarjanjua.github.io/signai/ to purchase or renew.

API Summary

Server endpoints:

  • GET /health
  • POST /v1/artifacts
  • GET /v1/artifacts/{monitor_id}
  • DELETE /v1/artifacts/{monitor_id}
  • POST /v1/score/inference
  • POST /v1/score/training
  • POST /v1/score/batch
  • POST /v1/calibrate/start
  • POST /v1/calibrate/push
  • POST /v1/calibrate/commit
  • GET /v1/history/{monitor_id}
  • POST /v1/notify/configure
  • GET /v1/audit/export
  • GET /v1/status
  • GET /v1/monitors
  • POST /v1/license

Model Support

Framework Status
PyTorch (CNN, ViT, ResNet, etc.) ✅ Supported
HuggingFace Transformers (BERT, GPT, LLaMA, etc.) ✅ Supported
Custom PyTorch architectures via extractor plugin ✅ Supported
TensorFlow / Keras Planned
JAX / Flax Planned
ONNX Planned
XGBoost / LightGBM / CatBoost Planned
PyG / DGL (graph neural networks) Planned

Privacy Model

signAI is built so that privacy is enforced structurally:

  • feature extraction runs on the customer machine
  • remote scoring receives only s and z float vectors (compact; typically <100 bytes per score call)
  • the server discards raw vectors after scoring
  • only {ts, score, flagged, phase} is stored in history
  • model weights, raw inputs, and gradients never leave the customer machine

Documentation

Development

Run the targeted test suite:

python -m pytest tests\test_imports.py tests\test_local_backend.py tests\test_monitor.py tests\test_server.py

Run the end-to-end and security test suite (isolated — does not touch ~/.signai):

python scripts\test_e2e.py

Licensing System

signAI uses Ed25519 asymmetric key signing. Keys are offline-verifiable — no network call on validation.

Key format: sk_<base64url(json_payload)>.<base64url(ed25519_sig)>

Payload fields: seat_id, email, plan, features[], model_limit, history_days, issued_at, expires_at

Enforcement: two checkpoints — signai/licensing.py (SDK client) and signai_server/usage.py (daemon). Both embed the public key as a hardcoded constant; the SIGNAI_PUBLIC_KEY_B64 env var is intentionally ignored (P0 bypass fix).

Clock integrity: both checkpoints carry a monotonic date ratchet (last_checked / last_validated). The effective date is max(today, last_recorded) — setting the system clock backwards has no effect on trial or key expiry.

Trial: 3 days from first install, tracked in ~/.signai/install.json.

Key Generation

Keys are generated via GitHub Actions only — the private key never leaves the keygen environment:

Actions → Generate License Key → Run workflow

For local testing with an ephemeral keypair:

python scripts\keygen.py genkeypair
python scripts\keygen.py generate --seat alice@acme.com --email alice@acme.com --plan individual --duration-days 30
python scripts\keygen.py verify sk_...

SIGNAI_PRIVATE_KEY_B64 must be set for generate. Never commit it.

Fulfillment

Automated: fulfill-orders.yml polls Stripe every 5 minutes, generates keys, and emails customers.

Manual fallback: see FULFILLMENT.md.

Stripe setup (one-time):

set STRIPE_SECRET_KEY=sk_live_...
python scripts\stripe_setup.py

GitHub Secrets required in the keygen environment: STRIPE_SECRET_KEY, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD, NOTIFY_EMAIL.

Release

Wheels are built via Cython + cibuildwheel on GitHub Actions — Python source is compiled into .so/.pyd binaries before publishing to PyPI. No source code ships in the wheel.

Tag a release: git tag v0.x.y && git push origin v0.x.y

The publish.yml workflow handles PyPI upload and Docker push to GHCR automatically.

License

Commercial license required. The private key and source code are confidential — do not share outside the team.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

signai_sdk-0.4.12-cp313-cp313-win_amd64.whl (5.5 MB view details)

Uploaded CPython 3.13Windows x86-64

signai_sdk-0.4.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

signai_sdk-0.4.12-cp313-cp313-macosx_11_0_arm64.whl (5.6 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

signai_sdk-0.4.12-cp313-cp313-macosx_10_13_x86_64.whl (5.7 MB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

signai_sdk-0.4.12-cp312-cp312-win_amd64.whl (5.5 MB view details)

Uploaded CPython 3.12Windows x86-64

signai_sdk-0.4.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

signai_sdk-0.4.12-cp312-cp312-macosx_11_0_arm64.whl (5.7 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

signai_sdk-0.4.12-cp312-cp312-macosx_10_13_x86_64.whl (5.7 MB view details)

Uploaded CPython 3.12macOS 10.13+ x86-64

signai_sdk-0.4.12-cp311-cp311-win_amd64.whl (5.5 MB view details)

Uploaded CPython 3.11Windows x86-64

signai_sdk-0.4.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

signai_sdk-0.4.12-cp311-cp311-macosx_11_0_arm64.whl (5.7 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

signai_sdk-0.4.12-cp311-cp311-macosx_10_9_x86_64.whl (5.7 MB view details)

Uploaded CPython 3.11macOS 10.9+ x86-64

signai_sdk-0.4.12-cp310-cp310-win_amd64.whl (5.5 MB view details)

Uploaded CPython 3.10Windows x86-64

signai_sdk-0.4.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (14.9 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

signai_sdk-0.4.12-cp310-cp310-macosx_11_0_arm64.whl (5.7 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

signai_sdk-0.4.12-cp310-cp310-macosx_10_9_x86_64.whl (5.7 MB view details)

Uploaded CPython 3.10macOS 10.9+ x86-64

File details

Details for the file signai_sdk-0.4.12-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 65e9a77f22773773fd96042dca40d509e393f7ec7ca4eb05d3a9c00e127890ee
MD5 045429a7485114dc9863b675dca3738d
BLAKE2b-256 569b7d22a27e80243e32199fd49f600fb6b7d2c7ec4b4d93a8ba5def82be196c

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 bf0dc09d4af35618940aac61f7aee938a3ce1bd5320e6e0f29209ab869fa440a
MD5 b16003a1e6ded2c996281c51fde4a565
BLAKE2b-256 ab4de9fd4484c637a878d86a69dbbe36da5c777c394f56c2ff16908d19948394

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2ba54d12ef2fe68a4c2db70eec5aa968e1edb191647c58a7a584cc6888a42e2d
MD5 acc66bc0adb2de7601f373ed118b0f4b
BLAKE2b-256 661d768a73bb7925d51ea7dcffd8c077f689a25706f76794a50e4c9283af83da

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 c441a2d4b84d8daf043a22a5057b85e0e1d9d712025e573e71ac9a3926c0c694
MD5 d93f93519beb3291208f9f7e6980ca68
BLAKE2b-256 af8b01b2cfa54a8fe3409784c104440f6b647729e94b2e5d2a2734f2e71269e4

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 40f49d91b46a1ff743a203f011d5931f939334655aa0f68c3e5d761b4d267d04
MD5 a4dc096c9d0317d65429123f42a3f46f
BLAKE2b-256 daae1f21725ef76544f1db3e65f9038a2cad3552b3af65e147bab58da7d16db4

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 26a89301e444d32700968ef74eacd74dac59a030eef5fa768d3eca043146aab8
MD5 24286f012416292c8d10717bc9cf480b
BLAKE2b-256 aa505d8f5e92dfa851cbccba1e152fa4a7a990dec88f604a885b1c6a8a79a413

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e84e789ba85bcf08b3d692e3c81d397f2d45535535ebcc869cdb2243c60d3c25
MD5 5c1dfbc0790ccfacfb50b2f9e6add0b4
BLAKE2b-256 424c2f095e23802996d66a9b56f74cc20dbea1517f39e471dc9e4a0a0eae8fbe

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp312-cp312-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 62c873be8caaae9abf7eb1a39a102bb898f4f630e5dbf1ee7335be013dc35851
MD5 35b400f81d3fabfcfe8cd8fdd0c1c05f
BLAKE2b-256 5443d9ec039ea42fdb71f22296b734e430b10689e6026bb42f3a424cf658d44e

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 0ba204c826c253232de20b4862cfe5c3b51031e2c464dfbe3f82b376eead3006
MD5 fc59b9a203cbbbfdcf35d001ed03a441
BLAKE2b-256 673b5d2905484f03608e13205dd76100bcdb4585440736d9bbe755662003a533

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c1986d1ebf274884c8880469f425b41fa611bd7d8862ef3a8d46a80f6c93b596
MD5 58ef71ca5cb29bc072f3ba72f35549a0
BLAKE2b-256 dbad38fb423e07464d3061501a1c37c78a90fe544b7c0a2b7567e0200d778c7c

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f04ed0395d8a5caffcb0c38ec4aab093f1229e4cbbc4f68ada52975e0da30434
MD5 7213a8e6faf16743215ae24b2b74c92c
BLAKE2b-256 a0aed48c53303f856cec09f2f91d1ae44acb91f2dcd2f8e0e86c42d05083749b

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 0fa502508cf9b383514a3350b6f4dc1778f1cfbdbeae48a30a2a9a0f93dd03ab
MD5 54395fb01b5acea6b32466ade4091790
BLAKE2b-256 c97133077181f7465d40fb53f735e45c06370025565d823cdf79311f39fe27d5

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 9d3a69b2474e64a5d392d393b24a96419182247991c3ae9d7563eca3af194e34
MD5 44e5445e35ece65a72529884243aeef0
BLAKE2b-256 a26502ff656398cde71ff6376030d276664df650d4974903d3e559e99e05c852

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 49bd6cb7bd93b4f543a13d613ede4b172a6498db8e6554707557b786b80c81be
MD5 66b67dd3a9d2f2c40c576f65c9f65c63
BLAKE2b-256 7a0920848684ac42d8cf75021f17af2da263f46f68ced57f1f5a7c39b763f8ac

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3cd5af95e22d9458fe5fd9ba379ff557e5bf2f5ea48ab70dd170c692f715e242
MD5 b8c3d925e2c65b78530e07960ee6f3cb
BLAKE2b-256 c328b82c53b42be16a48e3db608a2676cf2e2472caeecab9298efbde1b5eb121

See more details on using hashes here.

File details

Details for the file signai_sdk-0.4.12-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for signai_sdk-0.4.12-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 be6598e9dd0cf7219f1e99333ab6d27c44c1b7843797c20cf316f1ea57a13c2f
MD5 e07e9350ea30282abafcb438f7ef11bd
BLAKE2b-256 9c38fc726fb6af00ef7f96c289003400728dc0fc16b856707a4c34664d6d2b15

See more details on using hashes here.

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