Step 6: Agent Harness

A harness wraps a chat client with the scaffolding an agent needs to work through long, multi-step tasks — planning / execution modes, a todo list to plan against, context compaction, file memory, file access, and don't-ask-again tool approval. Instead of assembling those pieces yourself, you create a harness agent and get them out of the box.

Create a harness agent from any IChatClient with the AsHarnessAgent extension method. Because a harness works through tasks interactively over many steps, you typically drive it from a conversation loop: keep an AgentSession so the harness state (plan, todos, and history) persists across turns, read the user's next instruction, and stream the agent's output as it's produced.

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();
}

The harness handles planning, todo tracking, and history persistence for you across the whole conversation. For a full-featured console — with tool-approval prompts, todo/mode rendering, and slash commands — see the sample terminal UX.

Tip

See the .NET harness samples for full runnable applications.

The complete sample creates a Microsoft Foundry chat client, wraps it with create_harness_agent, and reuses one session across two turns. The harness adds planning, to-do tracking, and compaction while the sample disables file memory and web search to stay focused.

import asyncio

from agent_framework import create_harness_agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential


async def main() -> None:
    agent = create_harness_agent(
        client=FoundryChatClient(
            project_endpoint="https://your-account.services.ai.azure.com/api/projects/your-project",
            model="gpt-6-luna",
            credential=AzureCliCredential(),
        ),
        agent_instructions="Help users plan and complete multi-step tasks.",
        disable_file_memory=True,
        disable_web_search=True,
    )
    session = agent.create_session()

    print(await agent.run("Plan a weekend trip to Seattle.", session=session))
    print(await agent.run("Turn that plan into a checklist.", session=session))


if __name__ == "__main__":
    asyncio.run(main())

The shared session preserves the harness state across both calls. For a full-featured console - with tool-approval prompts, to-do and mode rendering, and slash commands - see the sample terminal UX.

Tip

See the full get-started sample. For more patterns, see the Python harness samples.

Tip

The agent-framework-builder-python coding-agent skill can guide harness composition and package choices. It is separate from runtime Agent Skills, which remain an opt-in Python harness capability.

Note

Go support for agent harnesses is coming soon. See the Agent Framework Go repository for the latest status.

Next steps

Go deeper:

  • Agent Harnesses — compaction, looping, shell, and the sample terminal UX
  • Agent Skills — progressively load skills from the file system