Browse the docs

Run a Claude skill as a Microsoft Foundry hosted agent

How a Claude skill runs unattended inside Foundry, with Agent Framework as the host and claude-agent-sdk as the brain, and reports to AMC.

Before you startA Claude skill folder (with SKILL.md) and a Microsoft Foundry project. Read [How agents connect](/developers/how-agents-connect/) first.View as Markdown

This path turns a Claude skill into a Foundry hosted agent. Foundry owns the endpoint, the sessions, the sandbox, scale-to-zero and Entra auth on the data plane. Inside the container, Microsoft Agent Framework (MAF) speaks the Foundry Responses protocol, and claude-agent-sdk runs the skill. AMC streams the run and shows it as steps, with tokens and cost per step.

The foundry-hybrid-agent-creator skill scaffolds the agent from templates. The templates already contain fixes for the failure modes agents of this shape hit in production, so a new agent starts with them instead of rediscovering them.

Why two layers

  • Not pure MAF: MAF's chat client reasons over a chat API. It can't load a SKILL.md, follow its method, run its scripts through Bash, or delegate through Task. Only the Claude Code CLI bundled in claude-agent-sdk can.
  • Not pure claude-agent-sdk: that gives you a self-hosted HTTP service where you own the endpoint and the auth. See Claude skill, self-hosted. The hybrid exists for when the agent must be a first-class Foundry resource: invocable over the Responses protocol, deployed as immutable versions, and visible to the platform and to AMC.

Architecture

Process tree inside the container
python3 main.py                      container entrypoint; Foundry starts this
  └── ResponsesHostServer :8088      agent-framework-foundry-hosting (MAF): HTTP + session only
        └── InvoiceSummarizerAgent(BaseAgent)
              │                      clientless shell: parse, Starting step, stream, envelope,
              │                      trailing markers, failed-run verdict, HITL plumbing
              ├── steps.StepReporter  maps tool calls to phase steps; copies produced items out
              └── runner.run_turn()   claude_agent_sdk.query(): the ONLY thing that reasons
                    └── claude (bundled CLI)  executes SKILL.md via the Skill tool
                          ├── Bash -> the skill's own scripts (gated by the PreToolUse hook)
                          ├── mcp__<server> -> the skill's integrations, as the instance identity
                          └── Task -> sub-agents, only if you enable them
LayerOwnsMust never
main.py (MAF hosting)HTTP on :8088, /readiness, sessionsAdd a /health route; reason
agent.py (MAF shell)Request parsing with defaults, refusal before spend, one turn at a time, the Starting … step, streaming, the envelope, trailing markers, the failed-run verdict, HITL plumbingHold a chat client, call a model, grow business logic
runner.py (brain wiring)The prompt, ClaudeAgentOptions, the tool-policy hook, the query() loop, the gates, host post-processing (publishing as plain I/O)Make judgments the skill owns
steps.py (host observer)Mapping tool calls to phases, copying produced items out of the skill's data files, per-phase token attributionAsk a model anything
The skillThe methodBe patched to fit the host

The rule that holds it together

MAF never reasons. The BaseAgent takes no chat client. The host may compute facts about the run (which tool was called, what a file contains, whether a regex matched) and enforce policy in code. It may not ask a model a question or compose content. Uploading the output after the turn is I/O, not reasoning, so the host does it. Having the model retype a large file through its output tokens is slow, costly and fails.

Claude models are reached through Foundry: CLAUDE_CODE_USE_FOUNDRY=1 and the agent's Entra instance identity. There is no API key in the sandbox.

What AMC sees

  • A Starting … step the moment the request is accepted, before any model call.
  • One step per skill phase, each with its own tokens and model.
  • One step per produced item, copied from the skill's own data files.
  • Host steps for publishing, red when refused.
  • Trailing per-model markers with the tokens no step claimed, cost and run totals.
  • A failed run ends response.failed, so AMC shows it as failed.
  • A run that completed with issues sends one run.outcome marker and ends response.completed, so AMC shows it as Completed with issues.

These are this path's way of meeting the integration contract. The rest of this section walks through each piece.

In this section

ArticleCovers
Prerequisites and project setupTools, Azure resources, the decisions to make first, vendoring the skill
Build the agent from the templatesEvery file, the request contract, the prompt, tool policy, gates, publishing
Invocation modes and session lifetimeStreaming, background, the 100 s cap, the session idle timeout
Run steps, token markers and costPhases, item steps, residual tokens, the failure marker, RunFailed
Human-in-the-loopPausing for a person and resuming with the answer
Choose models and spend ceilingsOrchestrator tier, sub-agents, deployment pins, ceilings
Deploy to FoundryBuild, deploy.py, identities and RBAC, version payload gotchas
Verify and register in AMCProbes in order, first real run, pricing, registration
TroubleshootingSymptoms, causes and fixes, and where the logs are

Last updated 2026-10-21