{"slug": "build-your-own-ai-agent-harness-in-c", "title": "Build Your Own AI Agent Harness in C#", "summary": "Microsoft is running a four-part live series, \"From Model to Agent: The Agent Framework Harness, Live in C#,\" streaming on the .NET YouTube channel and Microsoft Reactor on four consecutive Thursdays in September, in which a complete C# agent is built one capability at a time using the Microsoft Agent Framework agent harness. The series starts from a single call, chatClient.AsHarnessAgent(new HarnessAgentOptions {...}), and grows the same agent across four stages: tools, web search and planning; files, approvals and durable memory; skills, shell, CodeAct and background agents; and observability, governance, evaluations and hosted deployment in Microsoft Foundry. Two sessions are already available on demand and two more are coming.", "body_md": "A few weeks ago I wrote about going [from `dotnet run` to a Foundry Hosted Agent in three lines of C#](https://devblogs.microsoft.com/dotnet/from-dotnet-run-to-foundry-hosted-agent-in-3-lines-of-csharp/). The feedback was great. Developers liked the deployment story, the managed infrastructure, and especially the part where we did **not** spend the afternoon writing a Dockerfile, a session store, a telemetry pipeline, and a small distributed system just to expose one agent 😅.\n\nBut that post starts near the end of the journey. It assumes you already have an agent worth deploying.\n\nSo the next question is:\n\n“What should I put inside the agent before I deploy it?”\n\nTools. Planning. Safe file access. Human approval. Memory. Skills. Shell commands. Code execution. Background agents. Observability. Governance. Evaluations.\n\nThat list gets big very quickly.\n\nThe good news is that you do not need to build the runtime for all of it from scratch. Microsoft Agent Framework includes an **agent harness**, and I am building a complete C# agent with it live, one capability at a time, in a four-part series called **From Model to Agent: The Agent Framework Harness, Live in C#**.\n\nThe series streams live simultaneously on the **[.NET YouTube channel](https://www.youtube.com/@dotnet)** and **Microsoft Reactor**, four consecutive Thursdays in September, and every session stays available afterward on demand on both platforms. Two sessions are already available, and two more are coming. Let me show you what we are building and why the harness makes this much easier.\n\n## What we build across four sessions\n\nWe start with this:\n\n```\nAIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions\n{\n    ChatOptions = new ChatOptions\n    {\n        Instructions = instructions,\n        Tools = tools\n    }\n});\n```\n\nThen we grow the same agent through four stages:\n\n1. Give it tools, web search, and a plan.\n2. Let it work with files, approvals, and durable memory.\n3. Add skills, shell, CodeAct, and background agents.\n4. Add observability, governance, evaluations, and a hosted deployment.\n\nThat is the complete journey: from one call around an `IChatClient` to a capable agent that we can inspect, evaluate, govern, and run in Microsoft Foundry.\n\n## First: what is an agent harness?\n\nA language model can generate text. An agent needs more.\n\nIt needs a loop that can call tools, inspect the results, update a plan, remember useful information, request approval for risky actions, manage a growing context window, and keep working until the task is complete.\n\nThat surrounding runtime is the **harness**.\n\n**Where the term comes from**\n\n[Build your own claw and agent harness with Microsoft Agent Framework](https://devblogs.microsoft.com/agent-framework/build-your-own-claw-and-agent-harness-with-microsoft-agent-framework/)series. Their explanation is simple: a “claw” is a CLI-style agent built on top of a harness. You bring the model, instructions, and domain tools. The harness supplies the agentic machinery around them.\n\nIn .NET, the key line is this one:\n\n```\nAIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions\n{\n    ChatOptions = new ChatOptions\n    {\n        Instructions = \"You are a personal finance education assistant.\",\n        Tools = [StockTools.GetStockPrice]\n    }\n});\n```\n\nThat call gives the agent a complete pipeline with capabilities such as:\n\n- automatic function invocation\n- history persistence after model calls\n- planning with todo and agent-mode providers\n- context compaction\n- file memory\n- web search when the model service supports it\n- tool approvals\n- skills\n- OpenTelemetry instrumentation\n\nEach capability is configurable. You can replace it, disable it, or add your own provider.\n\nThat is the advantage of starting with the harness: you spend your time on what makes the agent useful, instead of rebuilding the same orchestration loop for every project.\n\n## The agent we are building\n\nAcross the four sessions, we build one personal finance education assistant.\n\nWhy finance? Because it gives us realistic boundaries to discuss:\n\n- Looking up a stock price is a read-only tool call.\n- Reading a portfolio means accessing user data.\n- Writing a report changes a file.\n- Placing a simulated trade is a side effect and needs approval.\n- Remembering a risk profile needs durable, user-scoped memory.\n- Calculating portfolio value is better done with code than model arithmetic.\n- Running shell commands requires confinement and policy.\n- A production finance agent needs traces, governance, and evaluations.\n\n**This is a learning scenario**\n\nThe complete code is in the [MafClaw sample repository](https://aka.ms/mafclaw/repo).\n\n## Session 1: turn a model into an agent\n\nIn [Meet Your Claw: A Harness in Three Lines of C#](https://www.youtube.com/watch?v=iUs15X1v2w4), we started with the smallest useful agent.\n\nFirst, create an `IChatClient` backed by a model in Microsoft Foundry:\n\n```\nIChatClient chatClient =\n    new AIProjectClient(new Uri(endpoint), new AzureCliCredential())\n        .GetProjectOpenAIClient()\n        .GetResponsesClient()\n        .AsIChatClient(model);\n```\n\nThen wrap it with the harness and give it one custom tool:\n\n```\nAIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions\n{\n    ChatOptions = new ChatOptions\n    {\n        Instructions = \"\"\"\n            You are a personal finance education assistant.\n            Use get_stock_price for stock prices.\n            Use hosted web search for recent market news and cite sources.\n            Use the todo list to track multi-step work.\n            \"\"\",\n        Tools = [StockTools.GetStockPrice]\n    }\n});\n```\n\nThe custom tool is ordinary C#. Agent Framework generates its tool schema from the function signature and descriptions:\n\n```\n[Description(\"Gets the illustrative stock price for a ticker symbol.\")]\npublic static string GetStockPriceBySymbol(\n    [Description(\"Stock ticker symbol, e.g. MSFT\")] string symbol)\n{\n    var upper = symbol.Trim().ToUpperInvariant();\n    return upper switch\n    {\n        \"MSFT\" => \"MSFT: 512.34 USD (mock)\",\n        \"NVDA\" => \"NVDA: 184.72 USD (mock)\",\n        \"AMZN\" => \"AMZN: 241.18 USD (mock)\",\n        _ => $\"{upper}: not available\"\n    };\n}\n\npublic static AIFunction GetStockPrice { get; } =\n    AIFunctionFactory.Create(\n        GetStockPriceBySymbol,\n        \"get_stock_price\");\n```\n\nNow the difference between a chat application and an agent becomes visible.\n\nAsk:\n\n```\nWhat is the price of MSFT?\n```\n\nThe model chooses the tool, the harness invokes it, the result returns to the model, and the agent produces the final answer.\n\nAsk something larger:\n\n```\nReview my watchlist and suggest what I should research next.\n```\n\nThe harness can create a plan and maintain a todo list while it works. We did not write a custom planning engine for the demo. We configured the behavior that makes this finance agent ours, and the harness supplied the planning runtime.\n\nThis first session is available now:\n\n## Session 2: work with user data safely\n\nAn agent becomes much more useful when it can work with your data.\n\nIt also becomes much more dangerous.\n\nIn [Working With Your Data, Safely: Files, Approvals and Memory](https://www.youtube.com/watch?v=V58coa0llUo), we gave the finance assistant access to a portfolio CSV, but only inside an approved working directory:\n\n``` js\nvar workingDirectory =\n    Path.Combine(AppContext.BaseDirectory, \"working\");\n\nAIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions\n{\n    FileAccessStore =\n        new FileSystemAgentFileStore(workingDirectory),\n\n    ChatOptions = new ChatOptions\n    {\n        Instructions = \"\"\"\n            The user's portfolio is in portfolio.csv.\n            Read it before answering portfolio questions.\n            Write generated reports under the approved working folder.\n            \"\"\",\n    }\n});\n```\n\nThe model does not receive arbitrary filesystem access. The application supplies a file store rooted at one folder, and the harness exposes file tools against that boundary.\n\nThis means the happy path works:\n\n```\nWhat is in my portfolio?\n```\n\nAnd the unsafe path is blocked:\n\n```\nRead C:\\some-other-folder\\outside-portfolio.csv\n```\n\nThe second boundary is human approval.\n\nA simulated trade is wrapped in `ApprovalRequiredAIFunction`:\n\n```\npublic static AIFunction RequestSimulatedTrade { get; } =\n    new ApprovalRequiredAIFunction(\n        AIFunctionFactory.Create(\n            RequestSimulatedTradeOrder,\n            \"request_simulated_trade\"));\n```\n\nThe model can request the action, but it cannot execute it directly. Harness emits an approval request first. The host application can show exactly which tool and arguments need approval, then return the human decision to the same agent session.\n\nWe also configured a low-friction safe path:\n\n```\nToolApprovalAgentOptions = new ToolApprovalAgentOptions\n{\n    AutoApprovalRules =\n    [\n        FileAccessProvider.ReadOnlyToolsAutoApprovalRule\n    ],\n},\n```\n\nRead-only file operations can proceed automatically. Writes, destructive operations, and the simulated trade still cross an approval boundary.\n\nThat distinction matters. If every harmless read interrupts the user, approval becomes noise. The goal is not to show more confirmation dialogs. The goal is to make consequential actions visible.\n\n### A question from the audience became a new sample\n\nDuring the live Q&A, someone asked:\n\n“What if the user does not answer the approval request?”\n\nGreat question.\n\n**Silence is not consent**\n\n`y`, immediate denial for `n`, automatic denial after the final attempt, sticky denial for the rest of the user prompt, and a limit on repeated approval rounds from the model.\nThe policy starts with a small configuration:\n\n``` js\nconst int maxApprovalAttempts = 5;\nvar approvalTimeout = TimeSpan.FromSeconds(5);\n\nvar approvalPolicy = new TimedApprovalPolicy(\n    maxApprovalAttempts,\n    approvalTimeout);\n```\n\nYou can find the complete implementation in [Sample 22: approval retries and timeouts](https://github.com/elbruno/mafclaw/tree/main/session-02/samples/22-approval-retries-timeouts).\n\nThe final part of Session 2 was memory. We compared local, application-owned JSON memory with managed Foundry Memory, and discussed why the model saying “I saved that” is not proof that anything was persisted. The application needs a real storage result, a scope, and a way to surface failures.\n\nSession 2 is also available now:\n\n[▶ Watch Session 2: Files, Approvals and Memory](https://www.youtube.com/watch?v=V58coa0llUo)\n\n## Session 3: skills, shell, CodeAct, and background agents\n\nThe first two sessions make the agent useful and safe. The third makes it more capable.\n\nIn [Scaling the Claw: Skills, Shell, CodeAct and Background Agents](https://www.youtube.com/watch?v=dCIBza-WxUc), we cover four different ways to expand an agent without turning its system prompt into a 400-page instruction manual:\n\n- **Skills** package domain knowledge in discoverable files. The agent sees a short description and loads the full instructions only when a request needs them, instead of stuffing every valuation and risk-scoring rule into the main prompt.\n- **Shell** access lets the agent perform tasks that are naturally expressed as commands, such as organizing files or inspecting a directory, inside a confined working directory with command policy, execution timeouts, and explicit approval.\n- **CodeAct** lets the agent write and run code in a controlled execution environment, which is more reliable and auditable than asking the model to perform arithmetic in prose.\n- **Background agents** let the main agent delegate independent research tasks, such as looking into MSFT, NVDA, and SPY in parallel, to separate agents that run concurrently and report back.\n\n**Confinement, not just approval**\n\nWe build all four live, with the finance assistant as the running example.\n\n[Watch or register for Session 3](https://www.youtube.com/watch?v=dCIBza-WxUc)\n\n## Session 4: make the agent production-ready\n\nAt this point the claw can plan, use tools, work with files, request approvals, remember facts, load skills, execute code, and delegate research.\n\nThat is the moment when somebody asks:\n\n“OK, the agent is done… now, how do I deploy this thing?”\n\nYes, we are back to the question from my previous post 😄.\n\nIn [Production Ready: Observability, Governance and Deployment](https://www.youtube.com/watch?v=rMhX0-oE4aY), we close the loop with:\n\n1. **Observability** with OpenTelemetry traces, tool calls, model calls, and token usage, so you can see what the agent actually did.\n2. **Governance** with Microsoft Purview policy integration, so organizational policy applies to agent behavior, not just human behavior.\n3. **Evaluations** for repeatable quality checks, so “it felt right in the demo” becomes a measurable signal.\n4. **Deployment** as a Foundry Hosted Agent, sharing one agent definition across a console app, a hosted endpoint, and an evaluation harness, each enabling only the capabilities appropriate for that host.\n\n**A production decision, not a framework limitation**\n\nThe exact deployment approach follows the container-hosting setup from the Agent Framework sample. My earlier [three-lines-of-C# post](https://devblogs.microsoft.com/dotnet/from-dotnet-run-to-foundry-hosted-agent-in-3-lines-of-csharp/) remains a useful introduction to the hosting model, but this claw has extra capabilities and therefore extra production decisions.\n\nWe build the observability, governance, evaluation, and deployment story live in this final session.\n\n[Watch or register for Session 4](https://www.youtube.com/watch?v=rMhX0-oE4aY)\n\n## Why start with the harness?\n\nYou can build every one of these pieces yourself.\n\nYou can write a tool loop, serialize history after every service call, maintain a plan, compact context, build a memory layer, design an approval protocol, load skills, manage background workers, and instrument the whole pipeline.\n\nSometimes you need that level of control.\n\nBut most teams want to spend their time on the domain behavior that makes the agent valuable:\n\n- What tools should it have?\n- What data can it access?\n- Which actions require approval?\n- What should it remember?\n- Which skills should it load?\n- Which tasks can run concurrently?\n- What policies apply?\n- How will we evaluate whether it works?\n\nThe harness gives those decisions a composable home.\n\nYou still own the boundaries. You still choose the tools. You still decide what gets approved, remembered, executed, traced, and deployed.\n\nYou just do not have to rebuild the agent runtime before answering any of those questions.\n\n## Join the series\n\nThe Microsoft Agent Framework blog has the complete written, .NET-and-Python version of this journey:\n\nAnd in the series, we build the .NET version live, one capability at a time, streaming live simultaneously on the [.NET YouTube channel](https://www.youtube.com/@dotnet) and Microsoft Reactor, four consecutive Thursdays in September, then staying available on demand on both platforms:\n\n1. [Meet Your Claw: A Harness in Three Lines of C#](https://www.youtube.com/watch?v=iUs15X1v2w4)\n2. [Working With Your Data, Safely: Files, Approvals and Memory](https://www.youtube.com/watch?v=V58coa0llUo)\n3. [Scaling the Claw: Skills, Shell, CodeAct and Background Agents](https://www.youtube.com/watch?v=dCIBza-WxUc)\n4. [Production Ready: Observability, Governance and Deployment](https://www.youtube.com/watch?v=rMhX0-oE4aY)\n\nBring your questions. The approval timeout sample exists because someone did exactly that.\n\n## Learn more\n\nHappy coding!\n\nBruno", "url": "https://wpnews.pro/news/build-your-own-ai-agent-harness-in-c", "canonical_source": "https://devblogs.microsoft.com/dotnet/build-your-own-ai-agent-harness-in-csharp-the-maf-claw-live-series/", "published_at": "2026-09-17 17:47:58+00:00", "updated_at": "2026-09-17 17:55:45.699601+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["Microsoft", "Microsoft Agent Framework", "Microsoft Foundry", ".NET YouTube channel", "Microsoft Reactor", "C#", "IChatClient", "HarnessAgentOptions"], "alternates": {"html": "https://wpnews.pro/news/build-your-own-ai-agent-harness-in-c", "markdown": "https://wpnews.pro/news/build-your-own-ai-agent-harness-in-c.md", "text": "https://wpnews.pro/news/build-your-own-ai-agent-harness-in-c.txt", "jsonld": "https://wpnews.pro/news/build-your-own-ai-agent-harness-in-c.jsonld"}}