diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index bee957de93e..27cf8605740 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -123,6 +123,7 @@
+
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/Claw_Step03_ScalingCapabilities.csproj b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/Claw_Step03_ScalingCapabilities.csproj
new file mode 100644
index 00000000000..3b5f9735d9d
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/Claw_Step03_ScalingCapabilities.csproj
@@ -0,0 +1,31 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
new file mode 100644
index 00000000000..aea7da4088f
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
@@ -0,0 +1,69 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Net.Http.Headers;
+using Azure.Core;
+using ModelContextProtocol.Client;
+
+namespace ClawSample;
+
+///
+/// Helpers for wiring centrally-managed Foundry skills into the claw via a Foundry Toolbox
+/// MCP endpoint. These are opt-in: skills published to the toolbox are discovered at runtime, so
+/// they can be managed and updated without changing or redeploying the agent.
+///
+internal static class FoundrySkills
+{
+ ///
+ /// Connects to a Foundry Toolbox MCP endpoint and returns a connected .
+ /// The caller owns the returned client and its HTTP client.
+ ///
+ /// The Foundry Toolbox MCP server URL.
+ /// Credential used to obtain a bearer token for the toolbox.
+ /// The connected MCP client and the underlying HTTP client; both must be disposed by the caller.
+ public static async Task<(McpClient McpClient, HttpClient HttpClient)> ConnectAsync(
+ string toolboxMcpServerUrl,
+ TokenCredential credential)
+ {
+ var httpClient = new HttpClient(new BearerTokenHandler(credential, "https://ai.azure.com/.default")
+ {
+ InnerHandler = new HttpClientHandler(),
+ });
+
+ try
+ {
+ McpClient mcpClient = await McpClient.CreateAsync(
+ new HttpClientTransport(
+ new HttpClientTransportOptions
+ {
+ Endpoint = new Uri(toolboxMcpServerUrl),
+ Name = "foundry_toolbox",
+ TransportMode = HttpTransportMode.StreamableHttp,
+ AdditionalHeaders = new Dictionary
+ {
+ ["Foundry-Features"] = "Toolboxes=V1Preview",
+ },
+ },
+ httpClient));
+
+ return (mcpClient, httpClient);
+ }
+ catch
+ {
+ // The MCP client never took ownership of the HTTP client, so dispose it here.
+ httpClient.Dispose();
+ throw;
+ }
+ }
+
+ private sealed class BearerTokenHandler(TokenCredential credential, string scope) : DelegatingHandler
+ {
+ private readonly TokenRequestContext _tokenContext = new([scope]);
+
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ AccessToken token = await credential.GetTokenAsync(this._tokenContext, cancellationToken).ConfigureAwait(false);
+ request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
+ return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
+ }
+ }
+}
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/Program.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/Program.cs
new file mode 100644
index 00000000000..54c05c49b0b
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/Program.cs
@@ -0,0 +1,228 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// "Scaling its capabilities" — Post 3 of the "Build your own claw and agent harness with Microsoft
+// Agent Framework" series.
+// See: https://devblogs.microsoft.com/agent-framework/agent-harness-scaling-the-claw-or-harness-capabilities/.
+//
+// This sample builds on Post 2's personal finance assistant and makes it *more capable* in four ways:
+// 1. Skills — package finance know-how (valuation, risk-scoring) as discoverable SKILL.md
+// files the agent loads on demand. Optionally fold in centrally-managed Foundry
+// skills from a Foundry Toolbox MCP endpoint (opt-in via FOUNDRY_TOOLBOX_MCP_SERVER_URL).
+// 2. Shell — a sandboxed shell, confined to the trade-confirmation vault, that the agent
+// uses to reorganize the accumulated confirmation files (year/month, rename,
+// archive). Guarded by a deny-list policy and a confined working directory.
+// 3. CodeAct — the agent writes and runs Python to crunch portfolio numbers, in a sandboxed
+// Hyperlight micro-VM (needs hardware virtualization).
+// 4. Background agents — fan out a per-ticker research sub-agent so several tickers are researched
+// concurrently, then aggregated.
+//
+// Special commands (handled by the shared HarnessConsole):
+// /todos — Display the current todo list without invoking the agent.
+// /mode — Get or set the current agent mode.
+// /exit — End the session.
+
+#pragma warning disable OPENAI001 // Suppress experimental API warnings for Responses API usage.
+#pragma warning disable MAAI001 // Suppress experimental API warnings for Agents AI experiments.
+
+using System.ClientModel.Primitives;
+using Azure.AI.Projects;
+using Azure.Identity;
+using ClawSample;
+using Harness.Shared.Console;
+using Harness.Shared.Console.OpenAI;
+using Harness.Shared.Console.ToolFormatters;
+using HyperlightSandbox.Guest.Python;
+using Microsoft.Agents.AI;
+using Microsoft.Agents.AI.Hyperlight;
+using Microsoft.Agents.AI.Tools.Shell;
+using Microsoft.Extensions.AI;
+
+var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
+var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4";
+
+// The two folders the claw works in: the working folder (portfolio.csv, reports) and the
+// trade-confirmation "vault" inside it that the shell will reorganize.
+var workingDir = Path.Combine(AppContext.BaseDirectory, "working");
+var vaultDir = Path.Combine(workingDir, "confirmations");
+var skillsDir = Path.Combine(AppContext.BaseDirectory, "skills");
+
+//
+var instructions =
+ """
+ ## Personal Finance Assistant Instructions
+
+ You are a personal finance and investing assistant. You help the user understand their
+ portfolio and watchlist, value individual stocks, gauge portfolio risk, research the market,
+ and keep their records tidy.
+
+ ### Working style
+
+ - The user's holdings live in a file called portfolio.csv. Read it with the file_access tools
+ before answering questions about their portfolio, and never modify it unless asked.
+ - You have skills for valuation and risk-scoring. When a question matches a skill, load it and
+ follow its instructions (read its references, run its scripts) rather than guessing.
+ - When asked to research several tickers, delegate each one to the background research agent so
+ they run concurrently, then summarize the findings together.
+ - The user's trade confirmations accumulate in the working/confirmations folder. When asked to
+ tidy or reorganize them, use the run_shell tool: inspect the folder first, then move files into
+ a year/month layout and rename them to YYYY-MM-DD_TICKER_BUY|SELL.txt. Explain your plan before
+ running commands that change anything.
+ - To buy or sell, use the place_trade tool. This takes a real action, so the user will be asked
+ to approve it before it runs — explain what you are about to do first.
+
+ ### Important
+
+ You provide information and analysis only — you are not a licensed financial advisor and you
+ must not present your output as personalized investment advice. Remind the user to do their own
+ research before making decisions.
+ """;
+//
+
+//
+// Construct an IChatClient backed by a Microsoft Foundry project (see Post 1 for details).
+var credential = new DefaultAzureCredential();
+var projectClient = new AIProjectClient(
+ new Uri(endpoint),
+ // WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
+ // In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
+ // latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
+ credential,
+ new AIProjectClientOptions { RetryPolicy = new ClientRetryPolicy(3) });
+
+IChatClient chatClient = projectClient
+ .GetProjectOpenAIClient()
+ .GetResponsesClient()
+ .AsIChatClient(deploymentName);
+//
+
+//
+// The harness turns a skills provider on by default (it discovers SKILL.md files from the working
+// directory). Here we build our own so we can point it at this sample's skills/ folder and, when
+// configured, fold in centrally-managed Foundry skills — all behind one provider.
+var skillsBuilder = new AgentSkillsProviderBuilder()
+ // File-based skills: valuation and risk-scoring. SubprocessScriptRunner runs their Python scripts.
+ .UseFileSkills([skillsDir], scriptRunner: new SubprocessScriptRunner().RunAsync);
+
+// Foundry skills (opt-in): discovered live from a Foundry Toolbox MCP endpoint, so they can be
+// managed and updated centrally without changing or redeploying this agent.
+HttpClient? toolboxHttpClient = null;
+ModelContextProtocol.Client.McpClient? toolboxMcpClient = null;
+var toolboxUrl = Environment.GetEnvironmentVariable("FOUNDRY_TOOLBOX_MCP_SERVER_URL");
+if (!string.IsNullOrWhiteSpace(toolboxUrl))
+{
+ (toolboxMcpClient, toolboxHttpClient) = await FoundrySkills.ConnectAsync(toolboxUrl, credential);
+ skillsBuilder.UseMcpSkills(toolboxMcpClient);
+ Console.WriteLine("Foundry skills enabled (Toolbox MCP).");
+}
+else
+{
+ Console.WriteLine("Foundry skills disabled. Set FOUNDRY_TOOLBOX_MCP_SERVER_URL to enable them.");
+}
+
+AgentSkillsProvider skillsProvider = skillsBuilder.Build();
+//
+
+//
+// Background agents: a lean, web-search-only research sub-agent. Passing it to the harness exposes
+// the background_agents_* tools so the claw can start several research tasks concurrently and
+// collect the results.
+AIAgent researchAgent = ResearchAgent.Create(chatClient);
+//
+
+//
+// A sandboxed shell, confined to the trade-confirmation vault. ConfineWorkingDirectory re-anchors
+// every command to the vault, and the deny-list policy pre-filters obviously destructive commands.
+// (Patterns are a UX guardrail, not a security boundary — for hard isolation use DockerShellExecutor.)
+await using var shell = new LocalShellExecutor(new LocalShellExecutorOptions
+{
+ WorkingDirectory = vaultDir,
+ ConfineWorkingDirectory = true,
+ Policy = new ShellPolicy(denyList:
+ [
+ @"\brm\s+-rf\b",
+ @"\bsudo\b",
+ @":\(\)\s*\{", // fork-bomb shape
+ @"\bmkfs\b",
+ @">\s*/dev/sd",
+ ]),
+ Timeout = TimeSpan.FromSeconds(15),
+});
+//
+
+//
+// CodeAct: a sandboxed Python interpreter the model can write and run code in to crunch numbers.
+// It runs on Hyperlight (a micro-VM, so it needs hardware virtualization). The guest module path is
+// resolved automatically from the Hyperlight.HyperlightSandbox.Guest.Python NuGet package.
+using var codeAct = new HyperlightCodeActProvider(HyperlightCodeActProviderOptions.CreateForWasm(PythonGuestModule.GetModulePath()));
+//
+
+//
+// Turn the chat client into a HarnessAgent. On top of Post 2's file access and approvals we add the
+// four "scaling" capabilities: skills (our own provider), background agents, a confined shell, and
+// CodeAct.
+List contextProviders = [skillsProvider, codeAct];
+
+AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
+{
+ // File access: portfolio.csv, reports, and the confirmations vault all live under working/.
+ FileAccessStore = new FileSystemAgentFileStore(workingDir),
+ // We supply our own skills provider (file + optional Foundry), so turn off the default one.
+ DisableAgentSkillsProvider = true,
+ // Fan-out research is delegated to this background agent.
+ BackgroundAgents = [researchAgent],
+ // The confined shell, exposed as the approval-gated run_shell tool.
+ ShellExecutor = shell,
+ // Keep reading the portfolio frictionless while writes, trades, and shell commands still prompt.
+ ToolApprovalAgentOptions = new ToolApprovalAgentOptions
+ {
+ AutoApprovalRules = [FileAccessProvider.ReadOnlyToolsAutoApprovalRule],
+ },
+ // Start in "execute" mode for quick lookups and actions; switch any time with /mode plan.
+ AgentModeProviderOptions = new AgentModeProviderOptions { DefaultMode = "execute" },
+ // Our skills provider plus CodeAct.
+ AIContextProviders = contextProviders,
+ ChatOptions = new ChatOptions
+ {
+ Instructions = instructions,
+ Tools =
+ [
+ StockTools.CreateGetStockPriceTool(),
+ TradingTools.CreatePlaceTradeTool(),
+ ],
+ Reasoning = new() { Effort = ReasoningEffort.Medium },
+ },
+});
+//
+
+try
+{
+ //
+ // Run the interactive console session. The default planning observers already include a tool
+ // approval observer, so the place_trade and run_shell approval prompts are surfaced automatically.
+ await HarnessConsole.RunAgentAsync(
+ agent,
+ userPrompt: "Ask me to value a stock, score your portfolio risk, research some tickers, or tidy your trade confirmations.",
+ new HarnessConsoleOptions
+ {
+ Observers = [
+ new OpenAIResponsesWebSearchDisplayObserver(),
+ new OpenAIResponsesErrorObserver(),
+ .. HarnessConsoleOptions.BuildObserversWithPlanning(
+ agent,
+ planModeName: "plan",
+ executionModeName: "execute",
+ toolFormatters: ToolCallFormatter.BuildDefaultToolFormatters())],
+ CommandHandlers = HarnessConsoleOptions.BuildDefaultCommandHandlers(agent),
+ });
+ //
+}
+finally
+{
+ codeAct?.Dispose();
+ if (toolboxMcpClient is not null)
+ {
+ await toolboxMcpClient.DisposeAsync().ConfigureAwait(false);
+ }
+
+ toolboxHttpClient?.Dispose();
+}
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/README.md b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/README.md
new file mode 100644
index 00000000000..8aeede2fe39
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/README.md
@@ -0,0 +1,80 @@
+# Scaling its capabilities (Post 3) — .NET
+
+The third runnable sample from the [**"Build your own claw and agent harness with Microsoft Agent Framework"** blog](https://devblogs.microsoft.com/agent-framework/build-your-own-claw-and-agent-harness-with-microsoft-agent-framework)
+series ([Part 3 — Scaling its capabilities](https://devblogs.microsoft.com/agent-framework/agent-harness-scaling-the-claw-or-harness-capabilities/)).
+It builds on Post 2's personal finance assistant and makes it *more capable* along four axes.
+
+## What this sample demonstrates
+
+- **Skills** — finance know-how (`valuation`, `risk-scoring`) is packaged as discoverable `SKILL.md`
+ files under `skills/`, which the agent loads on demand. The sample builds its own provider with
+ `AgentSkillsProviderBuilder.UseFileSkills([skillsDir], scriptRunner: new SubprocessScriptRunner().RunAsync)`
+ so the skills' Python scripts can run, and sets `DisableAgentSkillsProvider = true` to replace the
+ harness default. Optionally folds in centrally-managed **Foundry skills** discovered live from a
+ Foundry **Toolbox MCP** endpoint via `FoundrySkills.ConnectAsync(...)` + `UseMcpSkills(...)`
+ (opt-in; see below).
+- **Shell** — a `LocalShellExecutor` confined to the trade-confirmation vault
+ (`working/confirmations/`) lets the agent tidy the accumulated confirmation files (reorganize into
+ `year/month`, rename to `YYYY-MM-DD_TICKER_BUY|SELL.txt`). `ConfineWorkingDirectory` re-anchors
+ every command to the vault and a `ShellPolicy` deny-list pre-filters obviously destructive
+ commands. Exposed as the `run_shell` tool, which prompts for approval before each command runs.
+ (The deny-list is a UX guardrail, not a security boundary — for hard isolation use a
+ `DockerShellExecutor`.)
+- **CodeAct** — a `HyperlightCodeActProvider` gives the agent a sandboxed Python interpreter to
+ crunch portfolio numbers by writing and running code. It runs on Hyperlight (a micro-VM), so it
+ requires hardware virtualization. The guest module path is resolved automatically from the
+ `Hyperlight.HyperlightSandbox.Guest.Python` NuGet package via `PythonGuestModule.GetModulePath()`.
+- **Background agents** — a lean, web-search-only `ResearchAgent` is registered via
+ `HarnessAgentOptions.BackgroundAgents`, exposing the `background_agents_*` tools so the main agent
+ can fan out per-ticker research concurrently and aggregate the findings.
+
+## Prerequisites
+
+1. A Microsoft Foundry project with a deployed model (e.g. `gpt-5.4`).
+2. Azure CLI installed and authenticated (`az login`).
+3. *(For CodeAct)* a host with hardware virtualization enabled (Hyperlight runs the Python
+ interpreter in a micro-VM).
+
+## Environment variables
+
+```bash
+export FOUNDRY_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com/api/projects/your-project"
+# Optional (defaults to gpt-5.4)
+export FOUNDRY_MODEL="gpt-5.4"
+
+# Optional — enable centrally-managed Foundry skills (Foundry Toolbox MCP endpoint URL):
+export FOUNDRY_TOOLBOX_MCP_SERVER_URL="https://your-project.services.ai.azure.com/.../toolboxes/your-toolbox/mcp?api-version=v1"
+```
+
+When `FOUNDRY_TOOLBOX_MCP_SERVER_URL` is not set, the sample runs with the local file skills only and
+prints a note.
+
+## Running
+
+```bash
+cd dotnet
+dotnet run --project samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities
+```
+
+## What to expect
+
+The sample starts an interactive loop in **execute** mode (quick lookups don't need a plan). Try
+these in order:
+
+1. `Value MSFT for me.` — the agent loads the `valuation` skill and follows its instructions
+ (reading references and running its script).
+2. `Score the risk of my portfolio.` — the agent reads `portfolio.csv` and loads the `risk-scoring`
+ skill.
+3. `/mode plan`, then `Tidy up my trade confirmations.` — switching to plan mode first makes the
+ agent inspect `working/confirmations/` and propose a reorganization plan before touching anything;
+ once you approve it switches to execute and uses the shell to reorganize and rename the files,
+ **prompting you to approve** each command.
+4. `Work out the total value of my portfolio.` — the agent writes and runs Python via CodeAct.
+5. `Research MSFT, NVDA and SPY and summarize the latest news.` — the agent fans the tickers out to
+ the background research agent and aggregates the results.
+6. `What's the capital of France?` — with a `financial-agent-rules` skill published to your Foundry
+ toolbox and Foundry skills enabled (`FOUNDRY_TOOLBOX_MCP_SERVER_URL`), the agent loads it,
+ recognizes the question is off-topic, and politely declines, steering you back to finance.
+
+See the [Part 3 blog post](https://devblogs.microsoft.com/agent-framework/agent-harness-scaling-the-claw-or-harness-capabilities/)
+for more on the `financial-agent-rules` skill — including the SKILL.md to publish to your Foundry toolbox.
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/ResearchAgent.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/ResearchAgent.cs
new file mode 100644
index 00000000000..3d8ba56ff9c
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/ResearchAgent.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.AI;
+
+namespace ClawSample;
+
+///
+/// Builds the background "research" agent that the main claw fans work out to.
+///
+///
+/// This sub-agent doesn't need any of the harness machinery, so it's a plain
+/// with a single tool: the hosted web search. The parent claw
+/// delegates a per-ticker research task to one of these and they run concurrently.
+///
+internal static class ResearchAgent
+{
+ /// Creates a web-search-only background agent for delegated ticker research.
+ /// The chat client the background agent should use.
+ public static AIAgent Create(IChatClient chatClient) =>
+ chatClient.AsAIAgent(
+ instructions:
+ "You research a single stock ticker. Use the web search tool to find the most " +
+ "recent, relevant news and commentary, then return a short, factual summary " +
+ "(3-4 bullet points) with no preamble.",
+ name: "TickerResearchAgent",
+ description: "Searches the web for recent news and commentary about a single stock ticker.",
+ // The only tool it needs: the same hosted web search the harness would have added.
+ tools: [new HostedWebSearchTool()]);
+}
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/StockTools.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/StockTools.cs
new file mode 100644
index 00000000000..bbac78ac087
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/StockTools.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.ComponentModel;
+using Microsoft.Extensions.AI;
+
+namespace ClawSample;
+
+///
+/// A custom function tool that gives our "claw" access to (illustrative) stock prices.
+///
+///
+/// The prices and earnings figures returned here are mock data for demonstration purposes only and
+/// are not real market quotes. In a real assistant you would call a market-data API instead. The
+/// trailing earnings-per-share value is included so the valuation skill has something to work with.
+///
+internal static class StockTools
+{
+ /// A delayed, illustrative stock quote, including a trailing earnings-per-share figure.
+ public sealed record StockQuote(string Symbol, decimal Price, decimal TrailingEps, string Currency, DateTimeOffset AsOf);
+
+ // A tiny in-memory book of (price, trailing EPS) so the sample runs without any external dependency.
+ private static readonly Dictionary s_priceBook = new(StringComparer.OrdinalIgnoreCase)
+ {
+ ["MSFT"] = (462.97m, 11.80m),
+ ["AAPL"] = (229.35m, 6.13m),
+ ["GOOGL"] = (178.12m, 7.54m),
+ ["AMZN"] = (201.45m, 4.18m),
+ ["NVDA"] = (134.81m, 2.95m),
+ ["SPY"] = (612.40m, 23.10m),
+ };
+
+ ///
+ /// Gets the latest (delayed, illustrative) stock price and trailing EPS for a ticker symbol.
+ ///
+ /// The stock ticker symbol, e.g. MSFT or AAPL.
+ [Description("Gets the latest (delayed, illustrative) stock price and trailing earnings per share for a ticker symbol.")]
+ public static StockQuote GetStockPrice(
+ [Description("The stock ticker symbol, e.g. MSFT or AAPL.")] string symbol)
+ {
+ if (!s_priceBook.TryGetValue(symbol, out var data))
+ {
+ // Deterministic pseudo-values for unknown symbols so the sample stays self-contained.
+ // Derive a stable seed from the characters — string.GetHashCode() is randomized per
+ // process and Math.Abs(int.MinValue) throws, so neither is safe for repeatable output.
+ var seed = 0;
+ foreach (var ch in symbol.ToUpperInvariant())
+ {
+ seed = (seed * 31 + ch) % 1_000_000;
+ }
+
+ var price = 50m + seed % 45000 / 100m;
+ data = (price, Math.Round(price / 20m, 2));
+ }
+
+ return new StockQuote(symbol.ToUpperInvariant(), data.Price, data.Eps, "USD", DateTimeOffset.UtcNow);
+ }
+
+ /// Creates the wrapper used to expose the tool to the agent.
+ public static AIFunction CreateGetStockPriceTool() => AIFunctionFactory.Create(GetStockPrice, "get_stock_price");
+}
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/SubprocessScriptRunner.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/SubprocessScriptRunner.cs
new file mode 100644
index 00000000000..ae4e29c53fd
--- /dev/null
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/SubprocessScriptRunner.cs
@@ -0,0 +1,191 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// Sample subprocess-based skill script runner.
+// Executes file-based skill scripts as local subprocesses.
+// This is provided for demonstration purposes only.
+
+using System.Diagnostics;
+using System.Text.Json;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+
+///
+/// Executes file-based skill scripts as local subprocesses.
+///
+///
+/// This runner uses the script's absolute path and converts the arguments
+/// to CLI arguments. When the LLM sends a JSON array, each element is used
+/// as a positional argument. It is intended for demonstration purposes only.
+///
+internal sealed class SubprocessScriptRunner
+{
+ /// Maximum time a skill script is allowed to run before it is terminated.
+ private static readonly TimeSpan s_scriptTimeout = TimeSpan.FromSeconds(30);
+
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Optional logger factory. When provided, script outcomes (success output, stderr, non-zero
+ /// exit codes, and failures) are written to the log in addition to being returned to the LLM.
+ ///
+ public SubprocessScriptRunner(ILoggerFactory? loggerFactory = null)
+ {
+ this._logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger();
+ }
+
+ ///
+ /// Runs a skill script as a local subprocess.
+ ///
+ public async Task