Emissary.AspNetCore 0.1.0-preview.1

This is a prerelease version of Emissary.AspNetCore.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Emissary.AspNetCore --version 0.1.0-preview.1
                    
NuGet\Install-Package Emissary.AspNetCore -Version 0.1.0-preview.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="Emissary.AspNetCore" Version="0.1.0-preview.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Emissary.AspNetCore" Version="0.1.0-preview.1" />
                    
Directory.Packages.props
<PackageReference Include="Emissary.AspNetCore" />
                    
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 Emissary.AspNetCore --version 0.1.0-preview.1
                    
#r "nuget: Emissary.AspNetCore, 0.1.0-preview.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 Emissary.AspNetCore@0.1.0-preview.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=Emissary.AspNetCore&version=0.1.0-preview.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Emissary.AspNetCore&version=0.1.0-preview.1&prerelease
                    
Install as a Cake Tool

Emissary

Production-grade Claude agents for .NET — compile-time verified, provably safe, Native AOT.

CI NuGet License: MIT

Emissary is a Claude-native agent framework for modern C#. Where other frameworks discover agent mistakes in production, Emissary shifts correctness left: tool schemas and dispatchers are generated by the compiler, agent behavior is constrained by enforceable contracts, and every run is recordable, replayable, and assertable in CI — agents you can put in front of an auditor.

var options = new AgentOptions
{
    SystemPrompt = "You are a support agent. Verify identity before refunding.",
    Tools = { SupportTools.VerifyIdentityTool, SupportTools.RefundPaymentTool },
};
options.Rules.Require("refund_payment", prerequisite: "verify_identity");

var agent = new ClaudeAgent(options);
var result = await agent.RunAsync("Refund order A-1001, it arrived broken.");
Console.WriteLine(result.FinalText);

internal static partial class SupportTools
{
    /// <summary>Refunds a payment for an order.</summary>
    /// <param name="orderId">The order id.</param>
    /// <param name="amount">The amount to refund.</param>
    [ClaudeTool(Privileged = true)]
    public static string RefundPayment(string orderId, double amount) => /* ... */;
}

That [ClaudeTool] attribute is the whole integration: at compile time, a Roslyn source generator turns the method into a wire-ready tool — JSON Schema derived from the signature, descriptions harvested from the doc comments, and a strongly-typed dispatcher with zero reflection. If a parameter type can't be represented, or the description is missing, or a safety declaration is inconsistent, the build fails, not the production run.

Why Emissary

🛠 The compiler is the safety net. Tools, structured-output schemas, and argument binders are source-generated — no reflection anywhere in the pipeline. Analyzer diagnostics (EMS001EMS009) catch undescribed tools, unrepresentable types, and broken contracts in the IDE. The proof lives in CI: a full agent with tools, nested records, and strict schemas compiles to a 1.5 MB self-contained Native AOT binary on every commit.

🔒 Provable behavior, not prompt engineering. The answer to "how do you guarantee the agent can't do X?" is enforced machinery, all model-visible so Claude self-corrects:

  • Tool contractsRules.Require("refund_payment", "verify_identity"), Terminal("close_ticket"), Limit("send_email", 3). Violating calls never execute.
  • Taint tracking — output from Untrusted tools (web pages, documents, email) taints the run; Privileged tools are then blocked. Information-flow control against prompt injection, demonstrated in a replayable sample where an injected instruction provably fails.
  • RBAC[AuthorizeTool("payments")] tools are filtered before prompt construction: unauthorized callers' models never even see the schema. Deny by default.
  • Shadow mode — run the whole agent with privileged effects intercepted into a reviewable plan of effects instead of executed.
  • Human-in-the-loop gates — a gated call durably suspends the run (state serializes to JSON, survives restarts via SQLite); a webhook approval resumes it minutes or days later with contracts and taint state intact.
  • Compensation sagas[ClaudeTool(CompensatedBy = nameof(CancelReservation))] lets CompensateAsync unwind a run's effects in reverse order.

🔁 Deterministic testing for nondeterministic systems. Record any run as a .trajectory file; replay it byte-for-byte with zero network — real tools execute, drift throws a divergence error. Then assert on behavior:

EmissaryAssert.That(result)
    .ToolCalled("refund_payment", times: 1)
    .ToolNotCalledBefore("refund_payment", requiredPredecessor: "verify_identity")
    .NotTainted()
    .Stopped(AgentStopReason.Completed);

Golden trajectories run in CI as regression suites — Emissary's own test suite is the first customer.

🚀 Production plumbing included.

  • app.MapEmissaryAgent("/agent") — Server-Sent Events streaming out of ASP.NET Core minimal APIs; MapEmissaryApprovals is the resume webhook. Ships as a Native AOT container.
  • MCP server — your generated C# tools (or a whole agent) become Model Context Protocol tools callable from Claude Code and Claude Desktop: claude mcp add my-tools -- dotnet run ...
  • Prompt caching by default — automatic cache breakpoints (tools, system prompt, latest message) keep multi-turn cache hit rates high; cache economics are visible per run.
  • Token budgets — hard caps that stop a run before the next model call.
  • OpenTelemetry GenAI semantic conventionsinvoke_agent/chat/execute_tool spans, token and tool-call metrics. AddSource("Emissary") and it appears in Aspire.
  • Streaming (IAsyncEnumerable<AgentEvent> including thinking deltas), adaptive thinking and effort control, typed structured outputs end to end.

📐 An engineering bar you can audit. 100% line and branch coverage enforced by CI (with a public, per-line justified baseline for compiler artifacts — currently six entries), the AOT proof executed on every commit, every sample compiled on every commit, and architecture decisions recorded as ADRs.

Quick start

dotnet add package Emissary        # runtime + source generator, one package
export ANTHROPIC_API_KEY=...
using Emissary;

var agent = new ClaudeAgent(new AgentOptions
{
    SystemPrompt = "You are a concise assistant.",
    Tools = { MyTools.GetWeatherTool },
});

await foreach (var e in agent.StreamAsync("Weather in Oslo?"))
{
    if (e is AgentTextEvent text) Console.Write(text.Delta);
}

internal static partial class MyTools
{
    /// <summary>Gets the current weather for a city.</summary>
    /// <param name="city">The city name.</param>
    [ClaudeTool]
    public static string GetWeather(string city) => $"18°C and clear in {city}";
}

Typed structured outputs are the same pattern, in reverse:

/// <summary>A triaged support ticket.</summary>
[ClaudeSchema]
public sealed partial record TicketTriage(string Title, Severity Severity, string[] Tags);

var options = new AgentOptions { OutputSchemaJson = TicketTriage.JsonSchema };
var triage = result.FinalAs(MyJsonContext.Default.TicketTriage);  // guaranteed to conform

Packages

Package What it adds
Emissary The agent runtime + the [ClaudeTool]/[ClaudeSchema] source generator and analyzer
Emissary.Testing Framework-agnostic behavioral assertions for agent runs and replays
Emissary.AspNetCore SSE streaming endpoints and the human-approval webhook
Emissary.Mcp Expose tools or whole agents as an MCP stdio server
Emissary.Sqlite Durable suspended-run persistence for human-in-the-loop workflows

Samples

Nine runnable samples build in CI on every commit — documentation that cannot rot. Start at samples/01-HelloTool and walk forward; 04-RecordReplay and 06-ZeroTrustAgent run fully offline via bundled trajectories, no API key needed. The samples README has the map.

Design

Emissary is deliberately Claude-native, not provider-agnostic (ADR 0001): depth over breadth — prompt caching, thinking, compaction, and trajectory fidelity live in provider-specific details that neutral abstractions erase. Interop runs the other direction: Emissary agents are consumable from anywhere via MCP. It targets .NET 10 only, embraces C# 14, and releases are tag-driven (ADR 0005).

Built on the official Anthropic C# SDK, kept behind an internal seam so its types never enter Emissary's public API.

License

MIT

Product Compatible and additional computed target framework versions.
.NET 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. 
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.1.0-preview.4 59 8/24/2026
0.1.0-preview.3 63 8/24/2026
0.1.0-preview.2 71 8/22/2026
0.1.0-preview.1 63 8/22/2026