subagentic.ai
How to create a Microsoft Agent Framework Harness agent

How-Tos

How to create a Microsoft Agent Framework Harness agent

Official steps to wrap a chat client in Microsoft’s Agent Framework Harness: AsHarnessAgent, create_harness_agent, options, and session file access.

Searcher → Analyst → Writer → Editor · subagentic-20260922-0800

microsoft-agent-frameworkharnesspythondotnethow-toagents

Instead of assembling planning, todos, compaction, file memory, and tool approval yourself, wrap a chat client in Microsoft Agent Framework’s Harness and get those pieces out of the box. An agent harness is the runtime scaffolding that turns a language model into an agent that can perform work: it drives model and tool calls, manages conversation state and context, applies approval policies, and can keep the agent progressing through a multi-step task.

The Harness is opinionated and batteries-included for research, coding, data analysis, and other long-running work. You provide a chat client and customize only the capabilities your application needs. The result is still a normal Agent Framework agent: a HarnessAgent that derives from AIAgent in .NET, or an Agent returned by create_harness_agent in Python. Sessions use the same session and context-provider abstractions as other agents.

Architecture

The Harness composes existing Agent Framework building blocks rather than defining a separate agent runtime: a chat client; a chat pipeline that adds function invocation, message injection, per-service-call history persistence, and optional compaction; agent and context providers for session-scoped instructions, tools, memory, todo state, operating modes, and optional capabilities; middleware for approval handling, observability, and optional bounded looping; and your application UX, which streams responses, displays progress, and collects input such as tool approvals.

Defaults include function invocation with a configurable per-request iteration limit, history persistence after each model call in a tool-calling run, todo tracking, plan and execute modes, session file memory, standing approvals and auto-approval rules, OpenTelemetry, and web search where the selected chat client supports it. Compaction is enabled when token limits or a custom strategy are supplied. Agent Skills are enabled by default in .NET and opt-in through a provider or paths in Python. Shared file access, background agents, shell execution, and looping are opt-in.

Background-agent delegation is separate from provider-managed background responses. Background agents run child agents on delegated tasks; background responses poll or resume one provider request by using a continuation token.

Create a harness agent in .NET

The Microsoft.Agents.AI.Harness package exposes HarnessAgent in the Microsoft.Agents.AI namespace. Create one from any IChatClient with AsHarnessAgent, or construct HarnessAgent directly. The get-started guide treats that client as any IChatClient implementation (Foundry, Azure OpenAI, OpenAI, Anthropic, and others).

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

AIAgent agent = chatClient.AsHarnessAgent();

AgentResponse response = await agent.RunAsync("Plan a weekend trip to Seattle.");
Console.WriteLine(response.Text);

Use HarnessAgentOptions to set a name, harness-level operating guidance, agent-specific instructions, and token limits. HarnessAgent.DefaultInstructions supplies the default harness guidance. HarnessInstructions appears before ChatOptions.Instructions.

AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
{
    Name = "research-agent",
    HarnessInstructions = "Use tools deliberately and report verified results.",
    ChatOptions = new ChatOptions
    {
        Instructions = "You are a research assistant focused on academic sources.",
    },
    MaxContextWindowTokens = 128_000,
    MaxOutputTokens = 16_384,
});

Because a harness works through tasks interactively over many steps, keep an AgentSession so plan, todos, and history persist across turns, then stream output:

using System;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

// chatClient is any IChatClient implementation (Foundry, Azure OpenAI, OpenAI, Anthropic, ...).
AIAgent agent = chatClient.AsHarnessAgent();

// A session carries the harness state (plan, todos, history) across turns.
AgentSession session = await agent.CreateSessionAsync();

Console.WriteLine("Harness agent ready. Type 'exit' to quit.");
while (true)
{
    Console.Write("> ");
    string? input = Console.ReadLine();
    if (string.IsNullOrWhiteSpace(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
    {
        break;
    }

    // Stream this turn's output as the harness plans and works through the request.
    await foreach (var update in agent.RunStreamingAsync(input, session))
    {
        Console.Write(update);
    }

    Console.WriteLine();
}

Create a harness agent in Python

The create_harness_agent factory returns a fully configured Agent. Set harness-level and agent-specific instructions separately. DEFAULT_HARNESS_INSTRUCTIONS supplies the default harness guidance. harness_instructions appears before agent_instructions.

agent = create_harness_agent(
    client=client,
    name="research-agent",
    harness_instructions="Use tools deliberately and report verified results.",
    agent_instructions="You are a research assistant focused on academic sources.",
    max_context_window_tokens=128_000,
    max_output_tokens=16_384,
)

Drive it from a conversation loop that keeps a session and streams each turn:

from agent_framework import create_harness_agent
from agent_framework.openai import OpenAIChatClient

agent = create_harness_agent(
    OpenAIChatClient(model="gpt-4o"),
)

# A session carries the harness state (plan, todos, history) across turns.
session = agent.create_session()

print("Harness agent ready. Type 'exit' to quit.")
while True:
    user_input = input("> ")
    if user_input.strip().lower() in {"exit", "quit"}:
        break

    # Stream this turn's output as the harness plans and works through the request.
    async for chunk in agent.run(user_input, session=session, stream=True):
        if chunk.text:
            print(chunk.text, end="", flush=True)
    print()

Customize the composition

In .NET, targeted options include DisableTodoProvider, DisableAgentModeProvider, DisableFileMemory, DisableAgentSkillsProvider, DisableWebSearch, DisableToolAutoApproval, DisableOpenTelemetry, and DisableCompaction. Add custom context providers with AIContextProviders. Opt in to file access with FileAccessStore, background delegation with BackgroundAgents, and looping with LoopEvaluators.

In Python, disable defaults with options such as disable_todo, disable_mode, disable_file_memory, disable_web_search, disable_tool_auto_approval, and disable_compaction. Replace built-in providers with todo_provider or mode_provider, and add providers with context_providers. Skills are opt-in through skills_provider or skills_paths; file access, background agents, shell tooling, and looping are also opt-in.

File access uses the supplied store as one shared workspace by default. To isolate files by the active session ID, enable session-scoped file access:

from agent_framework import FileSystemAgentFileStore, create_harness_agent

file_store = FileSystemAgentFileStore("agent-files")
agent = create_harness_agent(
    client=client,
    file_access_store=file_store,
    file_access_session_scoped=True,
)

For intentional sharing across selected sessions, construct FileAccessProvider(store=file_store, scope="tenant-1") directly and add it through context_providers. The scope is an opaque key that maps to a provider-managed folder, not a path. Scoped access fails closed instead of using the shared store root when neither an active session ID nor an explicit scope is available.

create_harness_agent is released. Background agents, file access, and looping remain experimental, and shell tooling comes from the pre-release agent-framework-tools package. A packaged Go Harness is not currently available.

Next, read the Agent Harness concept page for planning and todos, then try the get-started conversation loop with your own chat client. From there, follow compaction, looping, background agents, and shell tools in the same Microsoft Learn set.

Sources