AI governance from prompt to proof
Self-hosted AI governance in one binary. Niyam sits in front of every model call, gates what AI agents are allowed to do, keeps sensitive data out of prompts and responses, and records every decision in a post-quantum-signed audit chain that a central control plane re-verifies. Security authors the rules in one place; every team's AI enrolls to that authority and cannot weaken it locally.
No SaaS. No data leaves your network. One niyam binary runs the central control plane (with
an embedded web console) or the data-plane enforcement, selected at startup. One SDK embeds the
same gate in your own agent code.
Two integration points: set your model client's base URL to the gateway, and wrap your
tool-dispatch in gate.dispatch(...). Policy, content safety, audit, and revocation are then
enforced centrally and recorded, without changing the rest of your app.
import niyam
gate = niyam.GovernedGate("http://control.internal:9090", "enrollment-token", "billing-agent")
decision = gate.dispatch(capability_token, "tools.payment.refund", "orders/8842")
if decision.allowed: # decided in-process, recorded in a signed audit chain
issue_refund()- One mode-selected static binary. The web console is compiled into it.
- Deterministic enforcement in the hot path. Models run only at the edges (content classifiers), never in the allow/deny decision.
- Post-quantum from day one: every signature and audit entry is ML-DSA-65 hybrid with Ed25519.
- SQLite by default (no database to run, one file to back up). Postgres for large fleets and HA.
- Measured on real cloud hardware: 58,000 to 77,000 policy checks per second on 4 cores; control-plane memory stays around 20 MB and flat while the audit record grows to gigabytes.
- Elastic License 2.0. Self-hosted only.
- The problem
- What Niyam does
- How it works
- The three enforcement boundaries
- Quick start
- Govern your own code: the SDK
- Author policy centrally
- Prove everything: audit and compliance
- What it runs like
- Enterprise operations
- Deployment profiles
- Install
- What is inside
- Documentation
- License
When an enterprise adopts AI, it has to answer the same operational questions for every team and every app:
- Who may call which model, and at what spend?
- What is an AI agent allowed to actually do: send an email, move money, delete a record?
- How do PII, PHI, and secrets stay out of prompts and out of responses?
- Can you prove, later and to an auditor, exactly what every AI did and why?
- Does any of that map to ISO 42001, the EU AI Act, or NIST AI RMF?
- Can security set these rules centrally, so one team cannot quietly turn them off?
The common answer is five to seven separate tools, wired in per application, that mostly log rather than block, and that any team can route around. That is observability, not governance. Niyam is the single product that enforces all six, centrally, in real time, and records the proof.
| The requirement | How Niyam meets it | Piece |
|---|---|---|
| One place to set the rules | Policy authored once, compiled, and distributed to every node | Lipi + control plane |
| Enforce the model call | An OpenAI-compatible gateway authenticates, gates, budgets, and forwards | Marg |
| Enforce the action | A deterministic gate + holder-bound capability tokens decide what agents may do | Kavach + Mudra |
| Protect the data | Prompt-injection, PII/PHI redaction, and output moderation on request and response | Drishti |
| Prove everything | Every decision lands in one post-quantum-signed audit chain, re-verified centrally | Kavach audit |
| Map to the law | Signed, auditor-ready evidence bundles per framework | Pramana |
| Test models continuously | Signed model and agent evaluation evidence | Pariksha |
| Central governs, teams cannot weaken it | Every node and SDK enrolls, pulls policy, and pushes audit; nothing overrides locally | Control plane |
Two planes and one rule: the centre decides, the edges enforce and prove.
+-----------------------------------------------+
| CONTROL PLANE |
| policy | keys | capability issuer |
| audit aggregation + independent re-verify |
| embedded web console + admin API |
+-----------------------------------------------+
^ enroll / pull policy / push audit
| (nodes and SDKs cannot weaken it)
+---------------+----------------+---------------------+
| | | |
+-----------+ +-----------+ +---------------+ +---------------+
| Gateway | | Gateway | | Safety server | | SDK gate |
| + safety | | + safety | | (GPU) | | in your app |
+-----------+ +-----------+ +---------------+ +---------------+
model calls model calls shared content your agent's
actions, data actions, data safety for a fleet actions
- The control plane holds the policy, the keys, the capability-token issuer, and the trust root. It aggregates every node's audit chain and re-verifies it independently. It serves the console and the admin API. Data-plane nodes and SDKs enroll to it, pull policy on a timer, and push their signed audit. They cannot author or relax policy.
- Data-plane nodes are the same binary in an enforcing mode: the gateway, content safety, and the action gate. They fail static: if the centre is unreachable they keep enforcing on the last policy they pulled and buffer their audit until it returns.
- Deterministic in the hot path. Every allow/deny is plain code. The only models in the system are Drishti's small content classifiers at the data boundary and build-time policy authoring, never a model deciding a request in real time.
- Post-quantum from day one. Every audit entry and token is signed ML-DSA-65 hybrid with Ed25519. The control plane pins each node's public bundle at enrollment and re-verifies every chain it receives against it.
Every AI touchpoint is blockable in real time, not merely logged.
Point any OpenAI-compatible client at the gateway. Each call is authenticated with a minted key, checked against policy (which models, which principals, what budget), recorded, and forwarded to your provider.
curl http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer $NIYAM_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hello"}]}'Adoption is one line: set the client's base URL to http://localhost:8080/v1. An unknown or
revoked key is 401; a model the policy does not permit is refused.
Actions are allowed or denied by policy in deterministic code. Agents carry capability tokens that are holder-bound (a bare bearer token is not enough), scoped to specific actions and resources, and revocable centrally within one refresh interval. The gate enforces on the gateway's live traffic and, identically, inside the SDK.
Three checks run on the request and the response: prompt-injection detection, PII/PHI redaction, and output-safety moderation. If the safety service is ever unreachable, the gateway blocks the call rather than letting it through ungoverned (the default; you can opt out).
prompt injection -> 422 blocked
"email a@b.com" -> forwarded as "[EMAIL]" (masked before it reaches the provider)
unsafe response -> 422 blocked
Safety runs embedded on the gateway's CPU, or as a shared safety-server (put it on a GPU) that
a fleet of gateways calls. The decisions are identical either way.
Stand up a control plane and a governed node with Docker:
cd deploy
docker compose up --buildThis starts the control plane (console and admin API on port 9090) and one data-plane node in
the full profile (governed gateway on port 8080), enrolled to the control plane. Open the
console at http://localhost:9090, sign in with the admin token, author a policy, mint a client
key, then point an OpenAI-compatible client at http://localhost:8080/v1.
For teams that embed the gate directly in their agent, the SDK is the same central gate as a
native module. Enroll once; wrap dispatch around your tool-dispatch layer. The decision is made
in-process (no network hop per call) and recorded in a post-quantum-signed audit chain that the
control plane re-verifies.
Python (pip install niyam-sdk):
import niyam
gate = niyam.GovernedGate("http://control.internal:9090", "enrollment-token", "billing-agent")
decision = gate.dispatch(capability_token, "tools.email.send", "mailbox/support")
if decision.allowed:
send_email()
else:
log_refusal(decision.reason)
gate.flush_audit() # push the signed record centrally
assert gate.verify_audit() # and it verifies locally tooNode (npm install niyam-sdk):
const { GovernedGate } = require('niyam-sdk')
const gate = GovernedGate.enroll('http://control.internal:9090', 'enrollment-token', 'billing-agent')
const decision = gate.dispatch(capabilityToken, 'tools.email.send', 'mailbox/support')
if (decision.allowed) sendEmail()dispatch enforces the token's signature, its scope and resource, the central policy, and the
revocation set, then records the decision. A central policy change or a token revocation reaches
every gate on its refresh interval; the same call then denies. Both SDKs are verified end to end
against a live control plane on every release.
Policy is authored once, centrally, and pulled by every node and SDK. An embedded gate can never weaken it.
# permit the support agent to send from one mailbox; everything else is deny by default
[[policy]]
name = "allow_support_email"
effect = "permit"
priority = 10
conditions = [ { action = "tools.email.*" } ]niyam ctl --token $ADMIN policy set policy.toml # raw policy
# or compile a single Lipi source to the policy plus an OPA Rego export and a review doc:
niyam ctl --token $ADMIN policy apply policy.lipiFine-grained, per-agent authority rides on capability tokens minted centrally:
niyam ctl --token $ADMIN agent create --name billing-agent
niyam ctl --token $ADMIN token mint \
--subject did:key:z6Mk... \
--scope 'tools.email.send=mailbox/support' \
--ttl-seconds 3600
niyam ctl --token $ADMIN token revoke --id <token-id> # denied everywhere within one intervalEvery decision, at the gateway or in the SDK, is appended to a hash-linked chain and signed ML-DSA-65 hybrid with Ed25519. The control plane holds each node's public bundle and re-verifies each chain it receives; a tampered or mis-signed segment is rejected and flagged, and the counter that tracks it is a first-class alert.
Pramana turns that record into auditor-ready evidence bundles mapped to ISO 42001, the EU AI Act, and NIST AI RMF, and Pariksha attaches signed model and agent evaluation evidence. Verification is offline: an auditor checks the signatures against the pinned issuer, without trusting the exporter.
Measured end to end on real cloud instances (see docs/CAPACITY.md for the
method and the full report).
| Path | Measured |
|---|---|
| Policy checks (control plane reads) | 58,000 to 77,000 per second on 4 cores, zero errors |
| Audit ingest (control plane writes, center-verified) | ~2,000 to 2,900 per second (SQLite), ~1,100 per second (Postgres) |
| Control-plane memory | ~20 MB and flat while the stored audit grows to gigabytes on disk |
| Gateway throughput (safety off) | ~980 (2c) / 1,770 (4c) / 2,870 (8c) / 3,820 (16c) requests per second |
| Content safety on a GPU (NVIDIA A40) | ~196 per second prompt-injection, ~100 per second output moderation |
| Content safety on CPU | 17 to 44 per second injection, 1 to 4 per second output (move it to a GPU service) |
| Embedded SDK gate | ~450 dispatch per second per vCPU, near-linear to ~4,500 per second at 8 cores |
Footprint:
- One static binary per OS and CPU. The control plane's resident memory stays bounded no matter how large the audit record grows: it keeps a small summary per node and reads chains from its store on demand.
- SQLite default means no external service to run and a single file to back up.
- Under failover, no audit records are lost: a data-plane node reconnects to the standby and resumes pushing from exactly where it stopped.
- High availability. An active control plane plus a warm standby on shared Postgres; the standby reconciles its cache on a timer. Killing the active keeps every gateway enforcing on cached policy, and on failover each node reconnects and resumes its audit push from its cursor. Validated live, with no lost records.
- Safe upgrades. The store carries a schema version and migrates forward on boot, and refuses to start against a store newer than the binary. The node-to-centre protocol is versioned, so an incompatible pair fails loudly instead of mis-governing.
- Observability. A Prometheus endpoint on both planes exposes governance signals as
first-class metrics: center-verify failures, dark nodes, safety fail-closed, store write errors,
and capability rejections. Alert rules and a Grafana dashboard ship in
deploy/observability/. - Pluggable store. SQLite (default) or Postgres behind one seam; the audit table is an append-only sink an OLAP system can read.
- Post-quantum. ML-DSA-65 hybrid with Ed25519 on every signature; hybrid verifiers reject PQ-only payloads and vice versa.
The same binary serves every role. Pick a profile with --profile:
| Profile | What runs | Serves |
|---|---|---|
control |
policy, keys, capability issuer, audit aggregation, console | 9090 |
gateway |
LLM gateway (Marg) plus Kavach gate plus PQ audit | 8080 |
safety |
gateway plus Drishti content safety (embedded) | 8080 |
full |
safety plus the Marg admin router | 8080 and /admin |
safety-server |
the content-safety models as a shared service (put it on a GPU) | 8443 |
gate |
the embedded action gate, as the SDK, inside your own app | in your app |
Every release ships one tested-together set of artifacts (niyam bom prints the exact pinned
versions). See CHANGELOG.md for what is in each release.
- Docker (the fastest way to run a node), from Docker Hub as
sarthiai/niyam(CPU) andsarthiai/niyam:latest-gpu(the GPU safety-server). Run a control plane, with the console and admin API on:9090:Change the admin and enrollment tokens in that config before real use, and pin a version tag (docker run -p 9090:9090 sarthiai/niyam \ run --profile control --config /etc/niyam/profiles/control.toml
sarthiai/niyam:0.1.0) in production. Ordocker compose upindeploy/to bring up a control plane plus a governed node together. Models are not baked in; a safety node fetches and verifies them at run time. - The
niyambinary. Download the archive for your OS and CPU from the Releases page, unpack it, and run./niyam. Prebuilt for macOS (Apple silicon), Linux (x86_64 and aarch64), and Windows (x86_64). The archive includes the profile templates andprovision-models.sh; thesafetyandfullprofiles need the ONNX runtime and models, which that script fetches (control and gateway need neither). - The SDK, to embed the gate in your own agent code:
- Python:
pip install niyam-sdk - Node:
npm install niyam-sdk
- Python:
To build from source instead, use the Quick start.
Niyam assembles three independent libraries, consumed as pinned crates.io dependencies, plus five pieces built in this repository:
- Kavach: the action gate and the post-quantum audit chain. The trust root.
- Marg: the LLM traffic gateway. It embeds Kavach.
- Drishti: content safety (prompt injection, PII and PHI, output safety).
- niyam-types: the shared contract (audit chain format, principal identity, policy artifact).
- Mudra: agent identity and post-quantum capability tokens, gated at the tool boundary.
- Lipi: the policy compiler. One source, compiled and distributed centrally.
- Pariksha: the evaluation harness. Signed model and agent evidence.
- Pramana: the regulatory mapper. ISO 42001, EU AI Act, and NIST evidence bundles.
The Kavach line Niyam pins equals the Kavach line Marg embeds, so the trust root is a single copy across the workspace, checked by a coherence gate on every release.
CHANGELOG.md: what shipped in each release.docs/ARCHITECTURE.md: the pieces, the two planes, and the trust model.docs/OPERATIONS.md: running, profiles, upgrades, HA, and the release pipeline.docs/CONFIGURATION.md: every config field, per profile.docs/SDK.md: embedding the gate in Python and Node.docs/API.md: the control-plane HTTP API.docs/SECURITY.md: the trust and threat model, and how to report an issue.docs/CAPACITY.md: measured capacity and cloud sizing.docs/NEGATIVE-TESTING.md: the fail-closed guarantees and how they were verified.deploy/README.md: Docker, Helm, and model-cache provisioning.
Elastic License 2.0 (LicenseRef-Elastic-2.0). See LICENSE. Self-hosted use;
your data and audit never leave your infrastructure.
Designed, developed, and maintained by Chirotpal
