ResponsibleAI.AgentControlSpec 0.4.0-beta.1

This is a prerelease version of ResponsibleAI.AgentControlSpec.
dotnet add package ResponsibleAI.AgentControlSpec --version 0.4.0-beta.1
                    
NuGet\Install-Package ResponsibleAI.AgentControlSpec -Version 0.4.0-beta.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ResponsibleAI.AgentControlSpec" Version="0.4.0-beta.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ResponsibleAI.AgentControlSpec" Version="0.4.0-beta.1" />
                    
Directory.Packages.props
<PackageReference Include="ResponsibleAI.AgentControlSpec" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ResponsibleAI.AgentControlSpec --version 0.4.0-beta.1
                    
#r "nuget: ResponsibleAI.AgentControlSpec, 0.4.0-beta.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ResponsibleAI.AgentControlSpec@0.4.0-beta.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ResponsibleAI.AgentControlSpec&version=0.4.0-beta.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ResponsibleAI.AgentControlSpec&version=0.4.0-beta.1&prerelease
                    
Install as a Cake Tool

Agent Control Specification .NET wrapper

ResponsibleAI.AgentControlSpec wraps the ACS policy decision engine as an agent-hooks interceptor (AcsInterceptor : IInterceptor). Every failure path is fail-closed (runtime_error:* deny).

using var acs = AcsInterceptor.FromPath("manifest.yaml", name: "acs");
var emitter = new InterceptionEmitter(EnforcementMode.Enforce);
emitter.Register(acs, "acs");

FromPath installs the bundled dispatchers: Rego in process, Cedar through the built-in evaluator, and the bundled annotators. The bundled annotators make HTTPS calls during evaluation when the manifest declares annotators, and evaluation blocks for the annotator budget. A manifest with no annotators makes no network call.

Install

dotnet add package ResponsibleAI.AgentControlSpec --prerelease

The package is pre-release, so --prerelease is required until a stable version ships.

Manifests can also be checked on their own, without building a runtime or having opa on PATH. Useful when generating or migrating manifests:

try
{
    AcsManifest.Validate(source);
}
catch (ManifestInvalidException error)
{
    Console.Error.WriteLine(error.Message); // names the offending field
}

A manifest that uses extends cannot be judged from its own source, because validation checks references across the merged document. Pass a path instead and the chain is resolved first:

AcsManifest.ValidateFile("manifest.yaml");

AcsManifest.SupportedVersions() reports the grammar versions this engine accepts. Read it rather than hardcoding the set.

Activating a policy version

AcsInterceptor readies a policy lazily, on the first emission. A host that pins a policy version and serves traffic against it wants the opposite split: pay to read and compile the bundle once, at a moment of its choosing, then evaluate a named intervention point with nothing left to set up. Compiling is bounded by the eval timeout: a policy too slow to compile in that window activates anyway, not necessarily fully readied, and pays compilation on its first evaluation instead. The bundled Rego runner reads the timeout from ACS_OPA_TIMEOUT_MS (default 5000 ms) once, when it starts, and applies it to every policy in the process; there is no per-policy setting:

using var policy = AcsPolicy.Activate("manifest.yaml");   // once per policy version
policy.Evaluate(InterceptionPoint.Input, contextJson);
policy.Evaluate(InterceptionPoint.PreToolCall, contextJson);

ActivatedPolicy is immutable and safe to evaluate from any number of threads at once; keep one per policy version rather than one per request. InterventionPoints reports the points the manifest binds, so a host can skip emitting where the policy does not govern:

if (policy.Governs(InterceptionPoint.PostToolCall))
    policy.Evaluate(InterceptionPoint.PostToolCall, contextJson);

A host that keeps manifests and Rego in a database has no path to give, and staging both to a temporary directory before every activation is work it should not have to do. ActivateFromMemory takes the manifest as text and the modules as values:

var bundles = new Dictionary<string, RegoBundle>
{
    ["gate"] = new RegoBundle
    {
        Modules = new Dictionary<string, string> { ["gate.rego"] = regoSource },
        Data = [new RegoDataDocument { Mount = ["limits"], Document = limits }],
    },
};

using var policy = AcsPolicy.ActivateFromMemory(manifestYaml, bundles);

Mount says where a data document lands under data; on disk that comes from the file's directory, and nothing implies it in memory. A RegoBundle carries source text and nothing compiled, so it costs microseconds to build and is not worth caching on its own. Cache the activated policy.

A Rego policy left naming a relative bundle or data path is refused: a manifest parsed from text has no directory of its own, so the path would resolve against the working directory and load a policy nobody chose. Write it absolute to keep it.

Disposal is deterministic, safe to repeat, and safe against evaluations already in flight. Evaluating an unbound point is not an exception; like every other failure it is a fail-closed deny, here with reason runtime_error:intervention_point_unknown.

A manifest names its policy bundle relative to itself, so the manifest path is the only one that has to be right; the host's working directory does not matter.

bench/ measures this surface: activation cost, warm p50/p95/p99, and throughput at concurrency 32. See bench/README.md.

Native libraries: the NuGet package carries agent_control_spec_ffi for linux-x64, linux-arm64, osx-x64, osx-arm64 and win-x64 under runtimes/, and the agent-hooks package carries agent_hooks_ffi the same way. Package users need no loader-path setup.

Source checkouts: build the engine binding with cargo build --release -p agent-control-spec-ffi, then run dotnet restore && dotnet test from sdk/dotnet with LD_LIBRARY_PATH (the platform loader path) pointing at target/release.

Product 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.0-beta.1 96 10/14/2026
0.4.0-alpha.4 85 9/26/2026
0.4.0-alpha.3 103 8/19/2026
0.4.0-alpha.2 95 8/7/2026
0.4.0-alpha.1 80 7/25/2026