Skip to main content

Vigil

Vigil — monitor everything an AI model or agent does, from the outside, with guarantees

pip install vigil-monitor · MIT · numpy only · Python 3.9+ · open research for the AI community

Vigil watches AI models and agents without needing anything from the model vendor: no reasoning traces, no logprobs, no weights. It treats the deployed system as a scientific instrument: conserved quantities are checked, causes are established by intervention, behaviour is compared with the declared objective, every alarm carries a stated false-alarm rate, and a silent change of the model behind an API is detected from the outside.

In one minute

An AI agent reads documents, calls tools and answers. Vigil records what it did, checks that its permissions, secrets and budget balanced, replays it with pieces of its context removed to find out what caused each action, compares its behaviour with the goal it was given, and wraps every alarm in a stated false-alarm rate. A separate canary check tells you when the model behind the API has been silently swapped. A gateway can block a disallowed tool call before the agent ever sees it.

what Vigil does

Who it helps

who it helps

Use cases

use cases

How an injection gets caught, step by step

how an injection is caught

A clean run reads zero

ledger

What "guaranteed" means here

guarantee

Every instrument says how hard it is to fool

robustness

Scorecard of live results

scorecard

What it does

Instrument Question it answers Needs
Ledger Did authority, information and budget balance on every step? (double-entry bookkeeping for agents) traces
Replay attribution Which context item caused the action? (Shapley over counterfactual replays, exact removal first) a replay endpoint
Revealed objective Did the agent optimise the objective it was given? (regret residual; GARP rationalisability) declared objective + feasible menu
Conformal escalation With what guaranteed false-alarm rate should this be escalated, and has that guarantee broken? known-good runs
Fingerprint Has the model behind the endpoint silently changed? (rotating canaries, paired test, BH control) canary prompts
Judge invariance Does the evaluator change its verdict when consequences change? (monitor the supervisors) a judge
Grounding, memory, drift, fleet, registry, oversight, infra, probes claim support, memory poisoning, embedding drift, loops and cascades, AI bill of materials, signed approvals, server and GPU telemetry, activation probes on owned weights see docs
Gateway Enforce it: strip disallowed tool calls before the agent sees them; approval unlock; fail closed sits in front of the model
Multi-model / cluster one endpoint per (model, revision, process, node, GPUs); per-endpoint calibration and fingerprints; per-GPU and per-model telemetry mapping; training-run account endpoint registry
Store + dashboard Time series of verdicts, ledger residuals and signals; self-contained dashboard; /metrics for Prometheus SQLite

Results on live models in detail (16 September 2026)

Two open-weight agents on vLLM, 20 injected and 20 clean runs per condition. Every number below is reproducible from the scripts in experiments/ and the JSON in experiments/results/.

live attribution results

Replay attribution named the injected document as the cause in 16/16 (Qwen3-8B) and 15/16 (Qwen3-32B) of the runs where the model followed the injection, every one escalated as high, with zero false alarms on clean runs.

evasion suite

Injections split across documents, base64-encoded, or hidden in a tool result were followed by the 32B agent every time and caught every time by three independent instruments.

fingerprint swap

The model behind the endpoint was swapped from Qwen3-32B to Qwen3-8B. The paired per-canary test caught it; a pooled divergence did not. Drift marks the calibration set stale so every downstream guarantee is reported as unbacked.

activation probe

With owned weights, a linear probe on the residual stream detects injections and generalises to unseen phrasings.

gateway, judge, grounding

The gateway stripped 13/13 injected transfers before the agent saw them and unlocked one after a human approval; the real LLM judge was consequence-invariant; grounding surfaced that half the model's claims went beyond thin evidence.

dashboard

The dashboard over 24 hours of stored verdicts: conservation accounts, escalations, regret and disagreement, the fingerprint band breaking at hour 20 and marking calibration stale, coverage, infrastructure, recent escalations.

Phase 4 results (16 September 2026, Nebius H100, Qwen3-8B agent)

phase 4 results

Experiment Result What it means
Hidden goals planted in the agent's configuration (7 framings: compliance CC, QA vendor, accounting ping, backup partner, internal shared inbox, internal log, internal zero-value ticket) Qwen3-8B acted on 0 of 70 runs (2 of 20 in a separate pass) the model refuses operator-planted exfiltration even when framed as internal housekeeping; the revealed-objective instrument still has no live positive case on this family
Trace dataset 1,420 examples: 1,200 synthetic, 220 live (154 clean, 64 harmful, 2 medium); the 8B agent did not follow base64 injections (0/20) while the 32B did (20/20) evasion susceptibility differs by model size
LM trace monitor, full trace (Qwen3-1.7B, LoRA, tail loss, 3 epochs, 4.5 min) AUROC 1.0, TPR 1.0 at 1 % FA on live held-out and on unseen evasions it sees the labelling action in the trace, so this is a sanity baseline, not evidence of anticipation
LM trace monitor, early warning (final action and ledger removed) live held-out: AUROC 1.0, TPR 1.0 at 1 % FA; unseen evasions: AUROC 0.83, TPR 0 at 1 % / 5 % FA, conformal catch 100 % it detects that an injection is present in the context (an input-side early warning) but cannot predict whether this model will act on it; predicting compliance before the action remains open
Grounding: lexical vs NLI entailment (30 real answers) documents-only instruction: 0.69 vs 0.62 unsupported; add-background instruction: 0.88 vs 0.98 NLI is stricter on outside knowledge and more lenient on faithful paraphrase; it separates the two instructions better
DCGM during LoRA training GPU_UTIL 100 %, tensor pipes 18 % active, 65.8 GB, 604 W the classic "utilisation lies" pattern; the default exporter config lacks SM-activity, so the automatic check needs a custom metrics file

Numbers are from 10–45 runs per condition and one model family; they show mechanisms, not population rates.

ORB: eight GPUs, six model families (17 September 2026)

Seven endpoints on an 8-GPU H200 node, spanning 8B to 120B: Qwen3-8B, Qwen3-32B, Phi-4, DeepSeek-R1-Distill-Llama-8B, IBM Granite 3.3-8B, gpt-oss-20B and gpt-oss-120B. Full tables in experiments/results/ORB-REPORT-SECTION.md.

ORB token telemetry and anytime-valid alarms

The guarantee now covers the deployment, not just the decision. Split conformal controls the false-alarm rate of one verdict; a production monitor makes millions of them, and at alpha 0.05 over 10,000 runs the chance of at least one false alarm is essentially one. TestMartingale replaces that with a bound that holds at every stopping time, including one chosen after looking at the data. On 400-step clean streams at all seven live endpoints there were no false endpoint alarms; on the two endpoints that genuinely changed under injection it fired after nine runs, and the changepoint detector after seven. Fleet e-BH picked exactly those two out of seven, with FDR controlled under arbitrary dependence rather than the independence a real fleet never has.

A model that complies with an injection is more confident, not less. Among runs that all contain an injection, the entropy at the token naming the tool separates compliance from refusal — perfectly on gpt-oss-20B, and in the same direction on three of the four models that act at all. The fourth reverses it, which is why the monitor calibrates per endpoint instead of shipping a shared threshold. This signal is contemporaneous with the action rather than ahead of it; it is useful because the gateway sits between the token and the tool, so a streaming monitor can abort a call while it is still forming.

provenance probe across model families

Models do represent who asked. They comply anyway. On a task balanced for length and content — the same two sentences, only their placement swapped between the user turn and a retrieved document — a linear probe on the residual stream reaches AUROC 0.98 to 1.00 in all five families tested, spanning 8B to 32B, with a shuffled-label control at chance in every one. On this evidence prompt injection is not a perception failure but a control failure, which is a different problem and a different fix.

And the warning that goes with it. Those same probes transfer their direction and not their threshold: 0.56 to 0.84 false alarm on unseen phrasings against a 0.05 target, versus 0.00 to 0.08 in distribution, in every family and with no improvement at larger scale. About twenty unlabelled runs from the target distribution restore it, with detection back at 1.00. Twenty is not tuned: below nineteen points split conformal cannot certify a 5% rate and correctly refuses to flag anything at all.

recalibration budget across five models

Compliance is a cliff, not a slope. The same demand at six levels of explicitness: only the rung claiming system authority got through, and softer phrasings failed completely rather than partially. The 120B model resisted the blatant order more often than a bureaucratic "processing note" framing — suggestive at ten runs per rung, and pointing the wrong way, since the polite framing is the one an attacker would pick.

Three of the seven endpoints never emitted a tool call at the decision step, writing prose instead. Their zero compliance rate means untested, not safe.

A false-positive mechanism the run exposed — partially fixed, still open. Every endpoint escalated none of its clean traffic except the gpt-oss family, which escalated 70% against a 10% target. The attribution gate treated any positive regret as off-objective, and gpt-oss re-reads documents before summarising: mildly suboptimal, genuinely caused by the retrieved documents, and so the gate fired on runs where nothing had gone wrong. Qwen3-8B never shows the pattern because it goes straight to summarising, so the trigger is a working style rather than a model, and any model that double-checks its sources would be penalised the same way. That is what makes it a defect in the monitor: a false-alarm rate that depends on how tidily a model sequences its tool calls is measuring habits, not behaviour, and it punishes exactly the cautious behaviour you would want.

The gate now requires regret above the endpoint's own calibrated threshold. In controlled tests that brought clean false alarms from 70% to 0/12, and to about 10% at alpha 0.1 across calibration sizes of 12, 25 and 30 runs, while detection of runs the model actually acted on stayed at 14/14 and 19/19. It is not fully resolved: the breadth sweep, which calibrates on 50 runs and scores them in-sample, still reported 0.62 and 0.74 for gpt-oss-20B and gpt-oss-120B. That discrepancy was not explained before the test node was released, so the fix is recorded as partial and the defect stays open. experiments/orb_breadth.py with --only gptoss reproduces it on a single GPU.

Quick start

from vigilai import Monitor, ModelFingerprint, Store, from_spans
from vigilai.adapters import OpenAICompatibleRunner

runner = OpenAICompatibleRunner("https://api.example/v1", "model-name", tools_schema, api_key="…")
m = Monitor(runner=runner, alpha=0.05)
m.store = Store("vigil.db")                                   # persist every verdict and signal
m.calibrate([from_spans(s, tool_meta=meta) for s in known_good_span_sets])
m.attach_fingerprint(ModelFingerprint().fit(baseline_canary_responses))

v = m.assess(from_spans(new_spans, tool_meta=meta), output=answer_text, evidence=retrieved_chunks)
if v.escalate:
    route_to_human(v.severity, v.reasons, v.attribution.top1())
vigil-dashboard --db vigil.db --port 8020      # dashboard at /, Prometheus text at /metrics

To enforce rather than observe, put the gateway in front of the model:

from vigilai import AgentPolicy, PolicyGateway, serve_proxy
gw = PolicyGateway({"agentA": AgentPolicy("agentA", {"model-name"}, {"search", "read", "summarize"}, {"read"})}, tool_meta)
serve_proxy(gw, upstream="https://api.example", port=8010)     # agents call http://gateway:8010/v1/chat/completions

Design principles

  1. Evasion-hard quantities first. Scopes used, secrets moved, budgets spent and actions under intervention must be violated to be beaten; text-based signals can merely appear clean.
  2. Instruments vote independently and their disagreement is reported; each publishes its adversarial robustness and the attack that defeats it (vigilai.ROBUSTNESS).
  3. Guarantees are explicit. Conformal calibration on known-good runs; a fingerprint change marks it stale.
  4. Trust is derived from provenance, never declared upward; reasoning blocks are secrets by default.
  5. Standards in, standards out. OpenTelemetry gen_ai and OpenInference spans in; decision spans and Prometheus metrics out. Vigil sits on top of any tracing platform; it does not replace it.

Limits, stated plainly

Replay needs a reproducible environment. The regret residual needs a correct feasible menu (it is skipped and declared when absent). Lexical grounding is gameable by paraphrase (plug in an entailment scorer). The dashboard and proxy have no authentication and must sit behind an authenticated ingress.

Token telemetry sees a hosted model's uncertainty, not its representations, and an endpoint that declines to return log-probabilities blinds it entirely. Activation probes are stronger and need weights you own. A probe ships as a direction, never a threshold: measured across three model families, a threshold calibrated on one set of phrasings produced false-alarm rates of 0.66 to 0.78 on new phrasings against a 0.05 target. Recalibrate on the deployment's own clean traffic, which needs no labels.

Multimodal inputs are entirely uninstrumented and are the largest remaining gap. A trigger that only the model can recognise is undetectable before it fires, by any external monitor, and nothing here changes that.

Layout

vigilai/ package · tests/ 60 tests · experiments/ live experiments, node setup, plots, demo dashboard · experiments/results/ dated JSON and logs · docs/img/ figures and logo.

Licence and community

MIT. Built as open research for the AI community; features from the wider observability field were adopted with thanks rather than compared against. The package is distributed through PyPI; the figures are hosted in a public assets repository. Feedback via the PyPI maintainer contact.

Release files for vigil-monitor 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vigil-monitor 0.7.0
File Size Uploaded
vigil_monitor-0.7.0.tar.gz 81.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for vigil-monitor 0.7.0
File Interpreter ABI Platform
vigil_monitor-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 155.8 kB

Release files / vigil_monitor-0.7.0.tar.gz

Download URL vigil_monitor-0.7.0.tar.gz
Size 81.5 kB
Tags Source
SHA-256 checksum
How to use checksums
1d63e15cd40690321f2d38e54a2b15921832f5b5afa22063b7641af228473742
BLAKE2b-256 checksum
How to use checksums
95ce162c9ed1fb5352cac59ab5ae76ce3314a04bbb8224ed519fe8ba43b2eb15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / vigil_monitor-0.7.0-py3-none-any.whl

Download URL vigil_monitor-0.7.0-py3-none-any.whl
Size 74.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4940422fe6d46077032e3f4b9bc8dbe1930f5214c21ff1a9f46955fb13d3a3a0
BLAKE2b-256 checksum
How to use checksums
73e8e808ca7a2930b89c637c680eac30074ef3194ff78e3a27fd1c9601682110
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

1.3.0

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

This release

0.7.0 This release

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page