Native C# SDK for building agentic AI. Inspired by the Strands Agents design principles. Community maintained.
The Jacquard loom — invented in 1804 — was the first machine to use punch cards to control patterns. It inspired Charles Babbage. It is the origin of the idea that a machine could be programmed to weave any pattern from simple instructions. That is what agents do: weave tools, models, loops, and prompts into intelligent behavior.
The .NET ecosystem is the dominant runtime in enterprise — Lambda functions, Windows services, ASP.NET APIs. When AWS released Strands Agents, the design was immediately compelling: model-driven event loop, clean tool system, hooks, multi-agent orchestration. But there was no native .NET implementation.
Jacquard.NET is that implementation. Built ground-up in C# 13. The same design principles as Strands Agents, expressed in the patterns .NET developers already know.
Four principles guide every decision:
- Don't over-engineer — if it doesn't need to be a feature, it isn't one
- Keep things clean — idiomatic C# throughout, no proprietary abstractions
- Embrace open standards — MCP and A2A native, not bolted on
- Be pragmatic about what to ship — production-useful, not academically complete
Five load-bearing technical pillars:
- Easy to learn, idiomatic to write — if you can write a C# method, you can write a tool. No new programming model, no middleware pipelines to learn before first invocation.
- Industry-standard vocabulary — agent, tool, system prompt, delta, session, hook. Reads natively to anyone from Strands Python, OpenAI, Anthropic, or LangChain.
- Zero runtime reflection — compile-time tool dispatch via Roslyn source generators.
JACQUARD001diagnostic catches misconfiguration at build time. - NativeAOT-ready — measured 89.6ms average cold-start init on AWS Lambda (arm64 Graviton2, 19/20 runs under 100ms). Reflection-free hot path designed for AOT publish.
- Multi-agent in one package — pipeline, parallel, graph orchestration, agent-as-tool, A2A protocol for cross-language interop.
dotnet add package Jacquard.Core
dotnet add package Jacquard.Models.Bedrock
dotnet add package Jacquard.Tools
dotnet add package Jacquard.SourceGenerator
Decorate a method with [Tool] on a partial class — the Roslyn source generator emits a compile-time ITool wrapper and an IToolProvider implementation automatically.
Single-file option — put the class declaration after the top-level statements:
using Jacquard.Core;
using Jacquard.Models.Bedrock;
using MyApp;
var agent = new Agent(
model: new BedrockModel("us-east-1"),
systemPrompt: "You are a helpful assistant.",
toolProviders: [new WeatherTools()]
);
var result = await agent.InvokeAsync("What's the weather in London?");
Console.WriteLine(result.Message);
// Type declarations must come after top-level statements in the same file.
// Use a block-body namespace (not file-scoped) when mixing with top-level statements.
namespace MyApp
{
public partial class WeatherTools
{
[Tool("Returns the current weather for a city")]
public string GetWeather(string city) => $"Sunny, 22°C in {city}";
}
}Two-file option — cleaner for larger projects:
WeatherTools.cs
using Jacquard.Core;
namespace MyApp;
public partial class WeatherTools
{
[Tool("Returns the current weather for a city")]
public string GetWeather(string city) => $"Sunny, 22°C in {city}";
}Program.cs
using Jacquard.Core;
using Jacquard.Models.Bedrock;
using MyApp;
var agent = new Agent(
model: new BedrockModel("us-east-1"),
systemPrompt: "You are a helpful assistant.",
toolProviders: [new WeatherTools()]
);
var result = await agent.InvokeAsync("What's the weather in London?");
Console.WriteLine(result.Message);The namespace on the
partial classis required. The source generator emits itsIToolProviderimplementation in the same namespace, and C# merges the two partial declarations into one type. Without a matching namespace they are treated as separate types and the build fails.Prerequisites: .NET 10 SDK, AWS credentials with Bedrock access enabled.
Four providers are included out of the box — swap in one line:
// Amazon Bedrock (cross-region inference profile)
var model = new BedrockModel(region: "us-east-1",
modelId: "us.anthropic.claude-haiku-4-5-20251001-v1:0");
// Anthropic direct API
var model = new AnthropicModel(apiKey: "sk-ant-...", modelId: "claude-sonnet-4-5");
// OpenAI / Azure OpenAI / Ollama / any OpenAI-compatible endpoint
var model = new OpenAICompatibleModel(
baseUrl: "https://api.openai.com/v1",
apiKey: "sk-...",
modelId: "gpt-4o");
// Google Gemini
var model = new GeminiModel(apiKey: "...", modelId: "gemini-2.5-flash");await foreach (var evt in agent.StreamAsync("Explain async/await in C#"))
{
if (evt is TextDeltaEvent delta)
Console.Write(delta.Delta);
}record WeatherReport(string City, int TempC, string Condition);
var report = await agent.GetStructuredOutputAsync<WeatherReport>(
"What is the weather in Paris right now?");
Console.WriteLine($"{report.City}: {report.TempC}°C, {report.Condition}");dotnet add package Jacquard.Extensions.DI
builder.Services
.AddBedrockModel(region: "us-east-1")
.AddHttpRequestTool()
.AddJacquardToolProvider<WeatherTools>()
.AddJacquardInMemorySessionManager()
.AddJacquardAgent();
// Resolve IAgent from the container
var agent = app.Services.GetRequiredService<IAgent>();- Model-driven event loop — the LLM decides which tools to call; the SDK executes them and loops until
EndTurn - Tool system — decorate any
partialclass method with[Tool]; the Roslyn source generator emits a compile-timeIToolwrapper with zero runtime reflection IToolProviderpattern — pass your tool class directly toAgentviatoolProviders:; no generated wrapper type names in user code;JACQUARD001warning guides non-partial classes- Streaming —
StreamAsyncreturnsIAsyncEnumerable<StreamEvent>end to end with[EnumeratorCancellation]on every boundary - Hook system — type-safe
Register<TEvent>callbacks forBeforeToolCall,AfterToolCall,BeforeModelCall,AfterModelCall - Human-in-the-loop — set
e.Interrupt = truein anyBeforeToolCallEventhook to pause before sensitive actions - Structured output —
GetStructuredOutputAsync<T>()extracts typed records with automatic JSON retry - Session management —
InMemorySessionManagerorFileSessionManager; bring your own viaISessionManager - Context window trimming —
SlidingWindowStrategyorSummarizingConversationManagerfor long-running agents - OpenTelemetry —
ActivitySourcenamed"Jacquard.Agent"emits traces and metrics with zero config - DI integration —
AddBedrockModel(),AddAnthropicModel(),AddOpenAICompatibleModel(),AddGeminiModel(),AddJacquardAgent(),AddJacquardToolProvider<T>()for native ASP.NET Core / Worker Service wiring - Multi-agent graph —
GraphBuilderwith conditional routing;PipelineOrchestrator;ParallelOrchestrator - Agent as tool — wrap any
IAgentas anIToolwithagent.AsTool()for hierarchical orchestration - MCP — connect any Model Context Protocol server (stdio or SSE) via
McpToolProvider - A2A protocol — expose agents over HTTP with
MapA2AEndpoint; call remote agents withA2AAgent(cross-framework, cross-language) - AgentCore Runtime (optional) —
MapAgentCoreEndpoints()deploys any agent to Amazon Bedrock AgentCore Runtime in one line;UseAgentCorePort(8080)binds the required port - AgentCore Memory (optional) —
AgentCoreMemoryTool/AddAgentCoreMemory()gives the agent explicit store/retrieve/delete access to Amazon Bedrock AgentCore Memory;AddAgentCoreSessionManager()persists conversation sessions to the same store - AgentCore Code Interpreter (optional) —
AgentCoreCodeInterpreterTool/AddAgentCoreCodeInterpreter()executes Python, JavaScript, or TypeScript in a managed, stateful sandbox; session is created lazily and reused across calls - AgentCore Browser (optional) —
AgentCoreBrowserTool/AddAgentCoreBrowser()manages a headless Chrome session; returns the CDPautomationStreamEndpointfor Playwright or Nova Act automation - AgentCore Gateway (optional) —
AgentCoreGatewayToolProvider/AddAgentCoreGatewayTools()connects to an Amazon Bedrock AgentCore Gateway MCP endpoint and exposes its tools asIToolinstances; supports IAM SigV4, JWT Bearer, and network-isolated (no-auth) modes
These aren't translations — they're the patterns .NET developers already know, applied to agentic AI.
| Capability | Jacquard.NET |
|---|---|
| Type safety | Compile-time generics |
| Streaming | IAsyncEnumerable<T> |
| Hook registration | Register<TEvent> — compiler-checked |
| Tool schema | Roslyn source generator at compile time |
| Tool registration | toolProviders: [new MyTools()] — no generated type names |
| Parallel execution | Task.WhenAll |
| DI integration | AddBedrockModel() + AddJacquardAgent() + AddJacquardToolProvider<T>() |
| Enterprise hosting | IHostedService / AWS Lambda / any host |
| Model providers | Bedrock, Anthropic, OpenAI-compatible, Gemini |
| MCP | ✓ |
| A2A protocol | ✓ (interoperable across languages and frameworks) |
| Graph orchestration | ✓ with parallel-node support |
| NativeAOT | ✓ (89.6ms avg cold-start on AWS Lambda arm64) |
var pipeline = new PipelineOrchestrator([researchAgent, writerAgent, reviewerAgent]);
var result = await pipeline.RunAsync("Write a report on quantum computing");var results = await new ParallelOrchestrator([techAgent, marketAgent, riskAgent])
.RunAsync("Analyse this topic from your specialist perspective");
// All three run concurrently via Task.WhenAllvar graph = new GraphBuilder()
.AddNode("triage", triageAgent)
.AddNode("billing", billingAgent)
.AddNode("technical", techAgent)
.AddConditionalEdge("triage", r =>
r.Message.Contains("billing") ? "billing" : "technical")
.Build();var researchTool = researchAgent.AsTool("researcher", "Research a topic and return a summary");
var writerAgent = new Agent(model, tools: [researchTool]);Connect your agent to tools hosted on an Amazon Bedrock AgentCore Gateway — a managed MCP endpoint that proxies external APIs, databases, and services with built-in auth and observability.
dotnet add package Jacquard.Runtime
// Direct usage — connect and list tools
await using var gateway = await AgentCoreGatewayToolProvider.CreateAsync(
gatewayUrl: new Uri("https://...gateway-url.../mcp"),
auth: new AgentCoreGatewayAuth.Iam(region: "us-east-1"));
var tools = await gateway.ListToolsAsync();
var agent = new Agent(model, tools: tools);Three auth modes match your gateway's inbound authorization setting:
// IAM SigV4 — credentials resolved from the standard AWS chain
new AgentCoreGatewayAuth.Iam(region: "us-east-1")
// JWT Bearer — Cognito, Entra ID, Okta, Google, GitHub, etc.
new AgentCoreGatewayAuth.Bearer(accessToken: token)
// No auth — network-isolated (VPC / security groups)
new AgentCoreGatewayAuth.None()With DI, AddAgentCoreGatewayTools() registers all gateway tools directly into the container — AddJacquardAgent() picks them up automatically:
builder.Services
.AddBedrockModel("us-east-1")
.AddAgentCoreGatewayTools(gatewayUrl, auth: new AgentCoreGatewayAuth.Iam("us-east-1"))
.AddJacquardAgent();Deploy any Jacquard.NET agent to Amazon Bedrock AgentCore Runtime with one line. Your agent code is unchanged.
dotnet add package Jacquard.Runtime
builder.Services
.AddBedrockModel("us-east-1")
.AddJacquardAgent();
var app = builder.Build();
app.MapAgentCoreEndpoints(); // POST /invocations + GET /health
app.UseAgentCorePort(8080); // AgentCore Runtime expects port 8080
app.Run();Optionally wire in managed AgentCore services before building the app:
builder.Services
.AddBedrockModel("us-east-1")
.AddAgentCoreSessionManager(memoryId)
.AddAgentCoreMemory(memoryId)
.AddAgentCoreCodeInterpreter()
.AddAgentCoreBrowser()
.AddJacquardAgent();| Package | Description |
|---|---|
Jacquard.Core |
Agent, event loop, tool system, hooks, session management, Gemini/Anthropic/OpenAI models |
Jacquard.Models.Bedrock |
Amazon Bedrock model provider (Converse API) |
Jacquard.Tools |
Built-in tools: calculator, file read/write, HTTP request |
Jacquard.SourceGenerator |
Roslyn source generator — emits ITool wrappers and IToolProvider from [Tool] attributes |
Jacquard.Extensions.DI |
ASP.NET Core / Worker Service DI extensions |
Jacquard.MultiAgent |
Pipeline, parallel, and graph orchestration; A2A protocol |
Jacquard.Runtime |
Amazon Bedrock AgentCore Runtime hosting; managed Memory, Code Interpreter, Browser, and Gateway tools |
| Sample | What it shows |
|---|---|
| CliAgent | Multi-turn streaming REPL — the minimal working agent |
| QuickstartSample | Built-in + custom tools, streaming — the canonical getting-started example |
| AspNetAgent | /chat endpoint with session continuity and SSE streaming |
| DiAgent | Full DI wiring with file tools and session management |
| FileAgent | FileReadTool / FileWriteTool + SlidingWindowStrategy context trimming |
| AutoTrimAssistant | Zero-boilerplate auto-trim via IAutoTrimConversationManager; file session with TTL |
| MultiAgentPipeline | Sequential pipeline + parallel fan-out with timestamps |
| OrchestratedResearch | All three orchestration patterns side by side |
| SupportTriage | Graph routing, hooks, and structured output extraction |
| CustomerServiceApi | Production-shaped REST API with session persistence |
| FinanceAssistant | 4-agent parallel swarm with typed report extraction |
| SwarmResearch | Dynamic swarm — 4 agents collaborate via autonomous handoffs; SwarmOrchestrator.StreamAsync with live console output |
| SwarmResearchWeb | Same swarm pattern as a web app — SSE endpoint + dark-theme browser UI with real-time agent pipeline and streaming text |
| PersistentAssistant | Cross-run memory with automatic summarization |
| DistributedAgents | A2A cross-process agent communication |
| ChatUI | Browser chat UI with SSE streaming and tool badges |
| BlazorResearch | Blazor Server portal with live parallel agent cards |
| ResponsibleAiSample | Bedrock Guardrails, [ToolParameterValidation], audit logging, least-privilege tool design |
| AotLambda | NativeAOT publish to AWS Lambda — 89.6ms avg cold-start (arm64 Graviton2, 14 MB binary) |
| DurableWorkflow | Decomposed Sequential Pipeline pattern — agent durability inside each invocation, workflow durability between invocations via Step Functions |
| CodeInterpreterSample | AgentCoreCodeInterpreterTool — stateful Python / JS / TS sandbox via AgentCore |
| BrowserSample | AgentCoreBrowserTool — managed headless Chrome session; CDP endpoint for Playwright / Nova Act |
| SemanticMemorySample | SemanticMemoryTool — vector / semantic search over AgentCore Memory |
| AgentCoreSample | Deploy any agent to AgentCore Runtime — MapAgentCoreEndpoints() in one line |
| AgentCoreGatewaySample | Travel booking assistant using gateway-hosted tools via AddAgentCoreGatewayTools() |
Jacquard.NET is a native C# SDK for building agentic AI, inspired by the Strands Agents design principles, independently maintained. The core concepts — model-driven event loop, tool system, hooks, multi-agent orchestration — are implemented ground-up in C# 13, with full interoperability via MCP and A2A.
Strands Agents is an open source SDK from AWS that takes a model-driven approach to building AI agents. The design principles that emerged from that work are sound and worth bringing natively to the .NET ecosystem. Jacquard.NET is that native implementation — not a port, not a wrapper, not a language bridge. Built using the types and patterns .NET developers already know.
This project is not affiliated with or endorsed by AWS.
PRs, issues, and feedback are welcome. See CONTRIBUTING.md for guidelines. The biggest areas of need are additional model providers (Ollama), more built-in tools, and real-world samples. Start a thread in Discussions before opening a large PR.
Apache 2.0. See LICENSE.