Skip to content

Packages

Affiant ships as ten co-versioned NuGet packages, all targeting net10.0. “Co-versioned” means a release publishes all ten together under one version number, and no package moves ahead of the others. It is a release convention, not a constraint NuGet enforces on your project — see Why one version number for the skew that is reachable and how to shut it out. Affiant.AgentFramework (the Microsoft Agent Framework bridge) joined the co-versioned set on 2026-07-05, Affiant.Extensions.AI (the Microsoft.Extensions.AI bridge) on 2026-08-20 — repository dates, not release dates. Affiant.AgentFramework’s NuGet id went live on 2026-07-31 and Affiant.Extensions.AI’s on 2026-08-20, and the first listed release, 1.0.0-beta.1 (2026-08-23), carried all ten, as has every listed release since.

The dependency graph is a strict DAG (directed acyclic graph — dependencies only point one way, never in a cycle) rooted at Affiant.Abstractions. This mirrors the Microsoft.Extensions.*.Abstractions / Microsoft.Extensions.* convention many .NET developers already know: reference Affiant.Abstractions alone if you only need to implement a contract — say, a custom IWriteExecutor for your domain — without pulling in any concrete service.

Package Role Key types
Affiant.Abstractions Domain-agnostic primitives and every backend-neutral contract a host implements. Three packages carry a public interface of their own — IManualToolInvoker (Affiant.SemanticKernel), IAffiantWrappedFunction (Affiant.Extensions.AI) and IAffiantHubClient (Affiant.Transport.SignalR) — and those three are the only public interfaces that ship outside this package. Zero dependencies on other Affiant packages. Affidavit, ProvenanceTag, ProvenanceChain, ToolEnvelope, DocketEntry, AffiantToolDescriptor, Operation, IWriteExecutor, IFieldMapper<T>, IDocketStore, IStreamingTransport, ITaskInferenceStrategy, IApprovalPolicy
Affiant.Core Concrete services: the Context Fabric, the Review Gate, inference orchestration, and telemetry. Where the framework’s actual logic lives. ContextFabric, ReviewGate, DeterministicShortCircuit, TaskInferenceStep, TaskInferenceRunner, SchemaDrivenAffidavitProjection, AffiantToolRegistry, AffiantTelemetry, and the neutral filters ReviewGateFilter, InferenceTriggerFilter, ToolArgumentCaptureFilter, TaskInferenceMergeFilter, ToolErrorFilter, ToolTracingFilter, plus the abstract ContextExtractor a host subclasses
Affiant.SemanticKernel The Semantic Kernel (SK) interception bridge — runs the backend-neutral tool-invocation pipeline at SK’s two filter positions (IFunctionInvocationFilter for the invocation-stage filters, IAutoFunctionInvocationFilter for the completion-stage ones), adds per-provider connector-capability probing, and runs hard-failure startup validation. See the honest boundary for exactly what this can and cannot see. AffiantFilterPipeline, AffiantAutoFunctionInvocationBridge, AffiantFunctionInvocationBridge, SemanticKernelInferenceCompletionPort, AffiantStartupValidator
Affiant.AgentFramework The Microsoft Agent Framework (MAF) interception bridge — translates MAF’s function-calling middleware into the same neutral pipeline. See Interception Backends. AffiantToolCatalog, AffiantFunctionInvocationMiddleware, AgentFrameworkInferenceCompletionPort, AgentFrameworkOptions
Affiant.Extensions.AI The Microsoft.Extensions.AI (M.E.AI) interception bridge — the abstraction both the Agent Framework and Semantic Kernel build on; SK’s chat abstraction (IChatCompletionService) and auto-invocation loop are its own, and an IChatClient converts to and from IChatCompletionService in either direction. Wraps each AIFunction in a DelegatingAIFunction that runs the neutral pipeline at M.E.AI’s own function-calling seam. Provider-neutral: references Microsoft.Extensions.AI only, never a concrete provider client. See Interception Backends. AffiantToolCatalog, AffiantDelegatingAIFunction, ExtensionsAIInferenceCompletionPort, ExtensionsAIOptions
Affiant.Docket The review queue’s backend-neutral half: the in-memory IDocketStore implementation, plus the background service that expires stale entries, warns on the ones about to lapse, and re-broadcasts the Evidence Card of every entry still pending — required for that shipped sweep whichever persistence backend you choose, and omittable only by a host that takes its store from elsewhere and calls IDocketStore.ExpireDueAsync on a schedule of its own. SQL-backed Docket storage lives in Affiant.EntityFramework (below), not here — it moved there in 1.0.0-beta.1. InMemoryDocketStore, DocketExpiryService, DocketOptions
Affiant.EntityFramework The EF Core persistence adapter — the shared DbContext, migrations, row-per-message chat session schema, and the SQLite/PostgreSQL IDocketStore implementations. Installing Affiant.Docket alone pulls in no EF Core, SQLite, or Npgsql — no published version of it ever has; only installing this package does. AffiantDbContext, AffiantMigrator, PostgresChatSessionStore, SqliteChatSessionStore, PostgresDocketStore, SqliteDocketStore, ChatSessionEntity, DocketEntryEntity
Affiant.Policies The approval-policy graph: auto-approval rules (Standing Orders), escalation rules (Referrals), and risk scoring, evaluated against every Affidavit as it is filed: a Standing Order that fires and clears the framework’s guardrails approves the entry outright, attested to the policy rather than to a person. The Evidence Card still goes out, marked RequiresConfirmation: false, so a reviewer surface can show what was approved with nobody present; what the entry never does is wait for a confirmation. Ships no scoring formula of its own — RiskScoreCalculatorBase is a host-supplied abstract class; DefaultRiskScoreCalculator, an earlier stock formula, was removed in 1.0.0-beta.1.1 for the opposite reason to the one you might expect: paired with StandingOrderBase’s then-default RiskThreshold of Low, it scored Medium or High on every path, so a Standing Order written to the documented contract could never auto-approve — every one of them fell through to reviewer confirmation. StandingOrderBase, ReferralRuleBase, RiskScoreCalculatorBase, RiskLevel
Affiant.Transport.SignalR The reference real-time transport — a subclassable SignalR hub plus an IStreamingTransport implementation for delivering Evidence Cards and streaming agent output. AffiantHub, SignalRStreamingTransport<THub>, SignalROptions
Affiant.Testing.ComplianceHarness A test helper, not a runtime dependency: verifies every registered write strategy has a paired fixture, and that the Affidavits it produces carry substantive provenance, not just well-shaped provenance. As of 1.0.0-beta.3 it also ships ConformanceSuite — the runner for the Affiant protocol’s own cross-implementation fixture suite, not the suite itself: the fixtures, fixture.schema.json and canonical-vector.schema.json are not in the package, and ConformanceSuite.Run reads them from a rulebook directory the caller vendors and passes in. What it then measures is whatever packages the project references — and the package picked up four references it did not carry at 1.0.0-beta.1.1: project references to Affiant.Docket and Affiant.Policies, and package references to JsonSchema.Net 7.3.4 and Microsoft.Extensions.Logging.Abstractions 10.0.5. A conformance run therefore files a proposal through the shipped ReviewGate, the shipped InMemoryDocketStore and the shipped ApprovalPolicyEvaluator, and validates every fixture and canonical vector against the rulebook’s own schema before running it. The policies the evaluator walks are the driver’s own FixturePolicy instances built from each fixture’s declaration, not types out of Affiant.Policies; the risk-ceiling comparison they apply is the framework’s, Affiant.Core.Services.StandingOrderGuardrails.ApplyRiskCeiling. See the Compliance Harness guide. ComplianceHarness, ComplianceVerificationResult, ConformanceSuite (the two types a compliance fixture is written against, ITaskInferenceComplianceFixture and InferenceFixtureCase, are in Affiant.Abstractions, so a host’s fixture compiles without referencing this package; a conformance fixture is a JSON document in the vendored rulebook directory, not a type)
Layer 0 Affiant.Abstractions (no Affiant dependencies)
Layer 1 Affiant.Core (→ Abstractions)
Layer 2 Affiant.SemanticKernel (→ Core)
Affiant.AgentFramework (→ Core)
Affiant.Extensions.AI (→ Core)
Affiant.Policies (→ Abstractions, Core)
Affiant.Transport.SignalR (→ Abstractions, Core)
Affiant.EntityFramework (→ Abstractions, Core)
Affiant.Docket (→ Abstractions, Core)
Layer 3 Affiant.Testing.ComplianceHarness (→ Core, Docket, Policies)

Each arrow is an edge the package declares for itself: the three interception bridges name Affiant.Core alone and pick up Affiant.Abstractions through it, while Affiant.Policies, Affiant.Transport.SignalR, Affiant.EntityFramework and Affiant.Docket name both. Either way Affiant.Abstractions is in the graph — the difference is only what each project file and nuspec spells out.

As of 1.0.0-beta.3, Affiant.Testing.ComplianceHarness sits a layer above the adapters rather than beside them: its new ConformanceSuite (see the Compliance Harness guide) files a proposal through the shipped ReviewGate, the shipped InMemoryDocketStore and the shipped ApprovalPolicyEvaluator to prove those packages behave the way the protocol’s rulebook says they must, so the test package references Affiant.Docket — whose InMemoryDocketStore and DocketExpiryService it resolves by name — in addition to Affiant.Core, which is where the gate and the evaluator themselves live. The third project reference, to Affiant.Policies, is declared by the project file and carried by the published package, but no source file in the harness names a type from it: the policies the conformance run walks are the driver’s own. Sitting above the adapters is what lets it hold all three edges without crossing the rule below, which governs packages at Layer 2 referencing one another — the framework’s own layering invariant does not place the harness in the graph at all. It is a test dependency either way: nothing in a host’s own production dependency graph references Affiant.Testing.ComplianceHarness.

Every package below Affiant.Core at Layer 2 sits at the same layer and never references any other package at that layer — Affiant.SemanticKernel, Affiant.AgentFramework, and Affiant.Extensions.AI are peers, none of them reference one another; Affiant.Docket and Affiant.EntityFramework are peers too. This is a change from a pre-release design: before 1.0.0-beta.1, Affiant.Docket depended directly on Affiant.EntityFramework for its SQLite- and PostgreSQL-backed stores, which forced an adapter-to-adapter dependency the framework’s own layering rule forbids. That edge was cut in 1.0.0-beta.1, so no published Affiant.Docket has ever carried it: the package implements only the in-memory store and the expiry sweep, and the SQL-backed IDocketStore implementations sit in Affiant.EntityFramework, next to the DbContext and entity configuration they were already built on. Installing Affiant.Docket alone therefore drags in no EF Core, SQLite, or Npgsql — see Docket & Evidence Cards for the registration mechanics this split implies.

A practical read of the graph: if you’re implementing a custom IFieldMapper<T> or IWriteExecutor for your domain, you need only Affiant.Abstractions. If you’re wiring up a host application end to end, you’ll typically pull in Affiant.Core, one interception bridge (Affiant.SemanticKernel, Affiant.AgentFramework, or Affiant.Extensions.AI — see Interception Backends for which one fits your host), Affiant.Docket for the in-memory store and the shipped expiry sweep, plus Affiant.EntityFramework if you want a durable Docket, Affiant.Policies if you want Standing Orders and Referrals, and Affiant.Transport.SignalR unless you’re supplying your own IStreamingTransport — see the FAQ on using Affiant without SignalR. A host that takes its IDocketStore from Affiant.EntityFramework and calls ExpireDueAsync on a schedule of its own — a serverless deployment with no long-lived process, a cron entry, a queue worker — can leave Affiant.Docket out: no framework package owns a timer that expiry depends on.

A library that only implements a contract — for example, a NuGet package providing an IFieldMapper<T> for a specific domain, published independently of any host application — needs nothing but the bottom of the graph:

Terminal window
dotnet add package Affiant.Abstractions --prerelease

That reference pulls in the interfaces and record types and nothing else: no Semantic Kernel runtime, no EF Core, no SignalR. This is deliberate — Affiant.Abstractions is the seam a host application never has to touch its dependencies to satisfy.

Affiant is in beta — install with the --prerelease flag rather than pinning an exact version suffix, so you always land on the current pre-1.0 release:

Terminal window
dotnet add package Affiant.Core --prerelease
dotnet add package Affiant.SemanticKernel --prerelease

Swap Affiant.SemanticKernel for Affiant.AgentFramework or Affiant.Extensions.AI if your host runs on a different backend — see Interception Backends to pick the right one. Add the other packages the same way as your host application needs them. See Installation for the full setup and Quickstart for wiring a first write tool end to end.

Co-versioning trades a small amount of install-size flexibility — you can’t take a bugfix in Affiant.Core without also being offered updated Affiant.Docket, Affiant.Policies, and so on — for a guarantee that matters more in a compliance-adjacent framework: any two Affiant packages taken from the same version number are contract-compatible with each other, full stop. You never have to consult a compatibility matrix to find out whether one package’s version works with another’s.

Nothing in the packaging enforces it, though. Each package declares its Affiant dependencies as a minimum-version floor — version="1.0.0-beta.3", not the exact pin [1.0.0-beta.3] — so a mixed graph is reachable in a consuming project, and the two directions behave differently. Bumping an adapter while leaving Affiant.Core behind fails the restore: error NU1605: Warning As Error: Detected package downgrade: Affiant.Core from 1.0.0-beta.3 to 1.0.0-beta.1, because the adapter asks for the newer Core and the direct reference pulls it back. Bumping Affiant.Core while leaving an adapter behind restores and builds without a word, because the older adapter’s floor is satisfied by the newer Core. Pin all ten to one version — a Directory.Packages.props, or one find-and-replace across the project files — and the guarantee above is the one you actually get; skew is only ever the consuming project’s own doing.

Trust the invariant — every Affidavit field carries provenance (Rule 7) — and expect the rest of the API surface, including these package boundaries, to keep evolving until 1.0 GA.