Invarix.Gate
1.0.0-rc.1
dotnet add package Invarix.Gate --version 1.0.0-rc.1
NuGet\Install-Package Invarix.Gate -Version 1.0.0-rc.1
<PackageReference Include="Invarix.Gate" Version="1.0.0-rc.1" />
<PackageVersion Include="Invarix.Gate" Version="1.0.0-rc.1" />
<PackageReference Include="Invarix.Gate" />
paket add Invarix.Gate --version 1.0.0-rc.1
#r "nuget: Invarix.Gate, 1.0.0-rc.1"
#:package Invarix.Gate@1.0.0-rc.1
#addin nuget:?package=Invarix.Gate&version=1.0.0-rc.1&prerelease
#tool nuget:?package=Invarix.Gate&version=1.0.0-rc.1&prerelease
Invarix.Gate
A deterministic action firewall for AI agents on .NET. It intercepts tool calls before they execute, checks them against a permission envelope, and blocks, escalates, or terminates the ones that would do damage.
No ML on the decision path. No outbound network calls. Verdicts in microseconds: a
median of 57 µs through the full default pack, measured once on one developer machine,
and every verdict carries its own ElapsedMicroseconds so you can check yours.
Install and run
dotnet add package Invarix.Gate --prerelease
dotnet add package Invarix.Gate.Extensions.AI --prerelease
Save the policy from "The policy" section below as gate-policy.yaml in the directory
your app runs from. A commented starter, gate-policy.sample.yaml, also sits at the
root of the Invarix.Gate package in your NuGet cache.
using Invarix.Gate;
using Microsoft.Extensions.AI;
var gate = GateEngine.Create(GateOptions.FromYaml("gate-policy.yaml"));
// Any Microsoft.Extensions.AI pipeline. Also covers MCP client tools, which are
// ordinary AIFunctions.
var client = innerClient.AsBuilder()
.UseInvarixGate(gate, agentId: "checkout-bot")
.Build();
Or with Microsoft Agent Framework:
dotnet add package Invarix.Gate.AgentFramework --prerelease
using Invarix.Gate;
using Microsoft.Agents.AI;
var agent = chatClientAgent.AsBuilder().UseInvarixGate(gate).Build();
That is the whole installation. Gate starts in observe mode, which blocks nothing.
One Agent Framework caveat: the call above gates tool calls, but token ceilings need
the chat boundary tapped, and Agent Framework's builder has no way to install that.
Wrap the IChatClient with UseInvarixGate before constructing the agent;
docs/COVERAGE.md shows the two lines.
What the first run tells you
── Invarix.Gate ── observe mode ── run 018f3c… ── agent deploy-bot ──────────
212 tool calls evaluated · 0 blocked (observe mode never blocks)
In enforce mode, this run would have seen:
IRREVERSIBLE (would require approval) 2 calls
destructive-sql db_execute DELETE without WHERE in statement 1 (matched: DELETE FROM orders)
git-history run_command git push --force rewrites the protected branch 'main'
HIGH-CONFIDENCE (would block) 1 call
secret-egress http_post AWS access key id in outbound argument "body" (matched: AKIA…)
CUMULATIVE (would warn / terminate)
limits.tokens 3.9M / 5M tokens (78%)
limits.calls 212 / 300 tool calls (71%)
runaway-loops poll_job_status called 41 times with identical arguments in the last 60s ×32
COVERAGE (within the wrapped pipeline)
14 tools registered · 14 routed through Gate · 0 calls observed outside Gate
3 tools called that are in no allowlist: http_post, db_execute, send_email
SUGGESTED NEXT STEPS (policy edits and diagnostics)
add "poll_job_status" to limits.loops.exempt if this tool is expected to repeat, such as status polling.
─────────────────────────────────────────────────────────────────────────────
Observe mode is the default because a safety tool that changes behaviour on install is one you cannot try in production. Read the report, tune the policy, then flip one line.
Multi-turn runs, and getting the report
Run identity is ambient. Without a scope, one response call is one run, which is right
for a single-turn request and wrong for a conversation: it hands per-run ceilings a
clean slate every turn. Open a GateRunScope around the conversation, and render the
report from the same identity when it ends:
using (GateRunScope.Begin("checkout-bot", runId))
{
// the conversation's turns
}
gate.EndRun("checkout-bot", runId);
Console.WriteLine(ConsoleReportRenderer.Render(gate.GetRunReport("checkout-bot", runId)));
MarkdownReportRenderer writes the same report as the markdown that survives being
committed or pasted into a pull request.
The policy
version: 1
mode: observe # flip to `enforce` to activate blocking (requires license)
limits:
per_run:
tool_calls: 300
tokens: 5_000_000
loops:
identical_calls: 5 # warn at 5, terminate the run at 10
window: 60s
agents:
deploy-bot:
tools: ["git_*", "read_file", "run_tests", "kubectl_*"]
strict: false # unlisted tools warn, never block, until you opt in
rules:
- use: destructive-sql
action: approve
- use: git-history
action: approve
protected_branches: [main, master, "release/*"]
- use: secret-egress
action: block
- id: no-prod-config-writes
tools: ["write_file", "edit_file"]
match_args: ["*/prod/*", "*.pfx"]
action: block
Every construct has a fluent C# equivalent with the same names. Full schema in
docs/POLICY-SPEC.md, which ships in this package.
What it catches
Ten detectors. Nine distill real incidents, most with public postmortems behind them.
gate-self-protection has no incident behind it yet, and shipping it is how that
stays true:
| Rule | What it stops |
|---|---|
destructive-sql |
DROP/TRUNCATE, DELETE/UPDATE without a WHERE |
shell-destruction |
rm -rf outside the workspace, del /s, Remove-Item -Recurse -Force, mass deletes |
git-history |
Force-push and history rewrites on protected branches |
cloud-teardown |
delete-stack, terminate-instances, terraform destroy, namespace deletes |
secret-egress |
API keys, private keys, JWTs, and connection strings headed outbound |
mass-send |
Sends to more recipients, or at a higher rate, than you meant |
runaway-loops |
Repetition, retry storms, and A-B-A-B agent ping-pong |
limits |
Per-run and per-agent call and token ceilings |
scope-allowlist |
Tools the agent was never supposed to have |
gate-self-protection |
The agent editing Gate's own policy, log, or license |
Irreversible-and-rare actions ask for approval rather than blocking, because a human waving through a rare dangerous call is cheap and a hard block on a call the operator wanted is how safety tooling gets uninstalled. Credential egress is the one class that blocks outright: its false-positive rate is the lowest and its harm window is too fast to wait for a human. Loops and budgets warn and then end the run, because denying one iteration of a loop just makes the loop retry.
What it does not catch
Gate protects tool calls that route through it and detects, but cannot prevent,
calls that do not. An agent wired around the interception point is unprotected, and the
coverage block in every report exists to make that visible rather than to be quietly
absent. docs/COVERAGE.md states the limits in full, including the ones that are
deliberate.
Gate is an action firewall. It does not inspect prompts or classify content: no prompt-injection detection, no PII, no topic boundaries. It composes with tools that do, including Invarix.Guard.
Free and Professional
Observe mode, the full detector pack, the report, the verdict log, and coverage detection are free under the Elastic License 2.0.
Enforce mode, approval workflows, and the evidence bridge are Professional: EUR 4,250, one payment, per company, all updates forever. No subscription, no seat counting, no support obligation (the docs in this package are the support channel).
services.AddInvarixGate(gate => gate
.Mode(GateMode.Enforce) // reads INVARIX_GATE_LICENSE
.UseDefaultPack());
Buy at invarix.dk/gate. Enforce mode fails loudly at startup without a valid license: it never silently downgrades to observe, because believing you are enforcing when you are not is the worst failure this product could have.
Documentation
docs/POLICY-SPEC.md: policy schema, glob and path semantics, precedence, failure behaviour, detector reference, and the compatibility promise.docs/COVERAGE.md: what Gate sees, what it cannot see, and how the coverage metric is scoped.docs/VERDICT-LOG.md: the JSONL wire format and the two hash specifications.
Security disclosures: security@invarix.dk. Sales: sales@invarix.dk.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- BouncyCastle.Cryptography (>= 2.6.2)
- Microsoft.Extensions.AI.Abstractions (>= 10.0.0 && < 12.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0 && < 12.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0 && < 12.0.0)
- YamlDotNet (>= 16.3.0)
-
net8.0
- BouncyCastle.Cryptography (>= 2.6.2)
- Microsoft.Extensions.AI.Abstractions (>= 10.0.0 && < 12.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0 && < 12.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0 && < 12.0.0)
- YamlDotNet (>= 16.3.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Invarix.Gate:
| Package | Downloads |
|---|---|
|
Invarix.Gate.Extensions.AI
Microsoft.Extensions.AI adapter for Invarix.Gate, the deterministic action firewall for AI agents on .NET. One UseInvarixGate() call on a ChatClientBuilder puts every tool call through the policy engine before it executes and taps the chat boundary for token usage, so per-run and per-agent ceilings see spend as it happens rather than after the run. MCP client tools are covered through the same interception point, because they are AIFunctions. Observe mode is the default and blocks nothing. Gate covers the tools invoked through the wrapped pipeline; the run report publishes what it could not see. |
|
|
Invarix.Gate.Evidence
Writes Invarix.Gate tool-call verdicts into an Invarix.Guard.Evidence decision log. Every verdict the action firewall renders becomes a CloudEvents 1.0 decision record: the tool that was asked for, the SHA-256 digest of the exact canonical arguments, each rule that matched as a detector result, the outcome, and the operator who approved or refused an escalation. Mapping runs on the tool-call thread and the write is handed to a bounded background queue, so an agent never waits on evidence I/O and a broken evidence store never breaks a run. Requires a commercial Gate license. |
|
|
Invarix.Gate.AspNetCore
Human approval over HTTP for Invarix.Gate. When a policy escalates a tool call, the broker posts a redacted approval request to a webhook and waits; an operator opens the confirmation page, reads what the agent is trying to do, and approves, denies, or stops the run. A GET only renders, so mail scanners and chat link previewers that prefetch the link cannot decide anything. Approval tokens carry 256 bits of entropy, are stored only as a SHA-256 hash, and are consumed once. The request payload and the page carry redacted findings, never raw tool arguments, so a credential-egress escalation is not itself the leak. Delivery to a broken webhook fails in seconds rather than absorbing the approval timeout. Requires a commercial Gate license. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-rc.1 | 74 | 8/6/2026 |