{"id":30639,"date":"2026-10-27T09:30:21","date_gmt":"2026-10-27T08:30:21","guid":{"rendered":"https:\/\/whiteduck.de\/running-flock-multi-agent-apps-as-microsoft-foundry-hosted-agents\/"},"modified":"2026-10-27T09:44:35","modified_gmt":"2026-10-27T08:44:35","slug":"running-flock-multi-agent-apps-as-microsoft-foundry-hosted-agents","status":"publish","type":"post","link":"https:\/\/whiteduck.de\/en\/running-flock-multi-agent-apps-as-microsoft-foundry-hosted-agents\/","title":{"rendered":"Running Flock Multi-Agent Apps as Microsoft Foundry Hosted Agents"},"content":{"rendered":"<p><a href=\"https:\/\/github.com\/whiteducksoftware\/flock\" target=\"_blank\" rel=\"noreferrer noopener\">Flock<\/a> is our open-source framework for multi-agent systems built on a blackboard. A Flock crew is a set of agents that react to typed artifacts on a shared blackboard, and the answer is whatever the crew publishes while the cascade runs. That model makes parallel work and joins almost free. It also makes hosting hard: put a crew behind a request\/response endpoint, and you have to answer which artifacts belong to which request, when a request is done, and what the caller gets to see.<\/p>\n<p>Microsoft Foundry hosted agents are the natural place to run such a crew on Azure. You package the agent as a container, and <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/agents\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">Foundry Agent Service<\/a> runs it behind an OpenAI-compatible Responses endpoint, with conversations, streaming, an Entra identity per agent and scaling handled by the platform. Microsoft documents that path for the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/how-to\/develop\/framework-hosted-agents\" target=\"_blank\" rel=\"noreferrer noopener\">Agent Framework<\/a> and <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/how-to\/develop\/langchain-hosted-agents\" target=\"_blank\" rel=\"noreferrer noopener\">LangGraph<\/a>, where a request enters one graph or agent loop and the answer comes out at its end. For a Flock crew, our position is simple: one request should be one isolated blackboard. With <code>flock-core<\/code> 0.5.700, Flock ships exactly that as  <code>FlockApplication<\/code>, plus a Foundry adapter in the new <code>flock-core[foundry]<\/code> extra.<\/p>\n<h2 id=\"FlockIn90Seconds\">Flock in 90 seconds<\/h2>\n<p> Flock is a <a href=\"https:\/\/whiteducksoftware.github.io\/flock\/\" target=\"_blank\" rel=\"noreferrer noopener\">blackboard architecture<\/a> for LLM agents. Agents do not call each other and nobody wires a graph. Each agent declares which artifact types it consumes and which it publishes, as Pydantic models, and Flock schedules it whenever a matching artifact lands on the blackboard. Parallelism and joins fall out of those contracts: two agents that consume the same type run concurrently, and an agent that consumes two types waits for both.<\/p>\n<p>Here is the incident-triage crew we use throughout this post, taken from the sample in the Flock repository:<\/p>\n<pre class=\"wp-block-code\"><code>from pydantic import BaseModel, Field\nfrom flock import Flock, WorkflowContext, flock_type\n\n\n@flock_type\nclass IncidentRequest(BaseModel):\n    report: str\n    history: list[dict[str, str]] = Field(default_factory=list)\n\n\n@flock_type\nclass IncidentTriage(BaseModel):\n    \"\"\"Internal: severity and affected component. Never returned to callers.\"\"\"\n\n    severity: str = Field(description=\"low, medium, high or critical\")\n    component: str = Field(description=\"The affected system component\")\n\n\n@flock_type\nclass IncidentSummary(BaseModel):\n    summary: str = Field(description=\"Two sentences for the on-call engineer\")\n\n\ndef build_flock(context: WorkflowContext) -&gt; Flock:\n    flock = Flock(\"azure\/incident-model\", no_output=True)\n    flock.agent(\"triage\").description(\n        \"Classify the incident report; use the conversation history for context.\"\n    ).consumes(IncidentRequest).publishes(IncidentTriage)\n    flock.agent(\"summarizer\").description(\n        \"Write a short, actionable summary for the on-call engineer.\"\n    ).consumes(IncidentTriage).publishes(IncidentSummary)\n    return flock\n<\/code><\/pre>\n<p><code>triage<\/code>  reacts to the request and publishes an <code>IncidentTriage<\/code>, which in turn triggers <code>summarizer<\/code>. The topology is a consequence of the types, not something we declared, and the same types double as the structured output schema for the model. <code>IncidentTriage<\/code> is an intermediate result: useful on the blackboard, but not something a caller should receive. For readability, this version uses Flock&#8217;s default engine; in the model access section we swap in an engine that authenticates with the hosted agent&#8217;s identity instead of an API key.<\/p>\n<p>Flock already had a way to serve a crew: <code>flock.serve()<\/code> runs one long-lived blackboard with a REST API and a live dashboard. That is the right tool for a shared workspace. It is the wrong tool for a hosted agent that answers independent requests from many users.<\/p>\n<h2 id=\"WhyHostingABlackboardIsDifferent\">Why hosting a blackboard is different<\/h2>\n<p> When we first put a Flock crew behind a Foundry endpoint, we wrapped one long-lived blackboard in a request handler. It worked in the demo and failed on four problems as soon as we thought about real traffic.<\/p>\n<ul>\n<li><strong>Shared state:<\/strong> one blackboard holds every caller&#8217;s artifacts, and batches, joins and context are keyed per agent, not per request.<\/li>\n<li><strong>Completion:<\/strong> a cascade has no final step, and only an explicit list of public outputs says which artifacts are the answer.<\/li>\n<li><strong>Failures and cancellation:<\/strong> every request needs one truthful outcome, with nothing left running and no exception text leaked.<\/li>\n<li><strong>Identity and capacity:<\/strong> the host has to know whose request it is and how many crews one container can afford.<\/li>\n<\/ul>\n<p>A durable store does not solve the first problem either. Our  <a href=\"https:\/\/whiteduck.de\/en\/flock-dapr-resilient-cloud-native-agent-swarms\/\">Dapr integration<\/a>  puts the blackboard into any Dapr state store, from Redis to PostgreSQL, so artifacts survive restarts and several instances can share them. That is exactly what we want for durability, and exactly why isolation cannot come from the store: a shared, durable blackboard keeps every caller&#8217;s artifacts for longer and makes them visible to more processes. Isolation has to come from how each request&#8217;s work is scoped.<\/p>\n<p>We solved these in our first hosted agent with locks, polling and custom error handling. That glue does not belong in every team&#8217;s hosting code. It belongs in the framework.<\/p>\n<h2 id=\"FlockApplicationOneRequestOneIsolatedWorkflow\">FlockApplication: one request, one isolated workflow<\/h2>\n<p><code>FlockApplication<\/code>  is the new transport-independent execution API in Flock. It turns a factory that builds a crew into something a host can call once per request. We call one such execution a <strong>workflow<\/strong>; Flock keeps the word &#8220;run&#8221; for a single agent task.<\/p>\n<p>The <a href=\"https:\/\/whiteducksoftware.github.io\/flock\/guides\/applications\/\" target=\"_blank\" rel=\"noreferrer noopener\">factory<\/a> builds a fresh <code>Flock(no_output=True)<\/code> for every workflow, so each workflow gets its own blackboard, its own scheduler state and its own MCP sessions. Nothing leaks between two concurrent requests, because they never share an instance. The workflow id becomes the correlation id of everything the workflow publishes, and agent context is restricted to that id whatever store and context provider the crew uses.<\/p>\n<p>That scoping is what makes the Dapr integration and per-request isolation work together. Isolation is logical, not physical: every workflow can write into one shared, durable store, while each workflow still only sees its own artifacts. The scoping applies to any Flock store, and we test it against a shared store with a context provider that deliberately queries everything. For the Dapr store, the factory just reuses one store instance:<\/p>\n<pre class=\"wp-block-code\"><code>from flock.storage import DaprStateBlackboardConfig, DaprStateBlackboardStore\n\n# One store per process: every workflow writes here, each sees only its own artifacts.\nSTORE = DaprStateBlackboardStore(DaprStateBlackboardConfig(store_name=\"flockstate\"))\n\n\ndef build_flock(context: WorkflowContext) -&gt; Flock:\n    flock = Flock(\"azure\/incident-model\", no_output=True, store=STORE)\n    ...  # agents as above\n    return flock\n<\/code><\/pre>\n<p>The store then holds every workflow&#8217;s artifacts, correlated by workflow id, for audit and replay; keep its administrative APIs private, because it contains every caller&#8217;s data. Dapr runs as a sidecar next to the application, which makes this a natural fit for your own host on Kubernetes or <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/container-apps\/dapr-overview\" target=\"_blank\" rel=\"noreferrer noopener\">Azure Container Apps<\/a>, with the <a href=\"https:\/\/whiteducksoftware.github.io\/flock\/guides\/dapr-state-store\/\" target=\"_blank\" rel=\"noreferrer noopener\">Dapr state store guide<\/a> covering the backends.<\/p>\n<p>The <strong>output contract<\/strong> is explicit. You declare the input type, the public output types and the outputs a successful workflow must produce. Flock never infers the answer from the agent graph, so internal artifacts stay internal: in our crew, <code>IncidentTriage<\/code> never leaves the workflow, and only the <code>IncidentSummary<\/code> is returned.<\/p>\n<p><strong>Completion<\/strong> defaults to quiescence: the workflow is done when no agent task and no timer is active. Partial batches are flushed once no producer remains, and joins that never completed are reported instead of waited for. If you need to stop earlier, <code>CompletionPolicy(until=...)<\/code> takes the same <code>Until<\/code> conditions Flock already uses, bound to the workflow automatically.<\/p>\n<p>Every workflow ends with exactly one <code>WorkflowResult<\/code>: <code>succeeded<\/code>, <code>failed<\/code>, <code>cancelled<\/code> or <code>timed_out<\/code>. Failure codes such as  <code>agent_failed<\/code>  or <code>required_output_missing<\/code> carry fixed, safe text. Exception text never reaches the caller, because it can contain private input.<\/p>\n<p>Around that core, the application handles the operational details we used to hand-roll: deadlines, cancellation with bounded teardown, a concurrency limit that rejects instead of queueing, protection against a retried request starting the same work twice, and a conversation mode that runs turns of the same session one at a time.<\/p>\n<pre class=\"wp-block-code\"><code>from flock import FlockApplication, WorkflowContext\n\napplication = FlockApplication(\n    factory=build_flock,\n    input_type=IncidentRequest,\n    output_types=(IncidentSummary,),           # the public answer\n    required_output_types=(IncidentSummary,),  # success requires it\n    default_timeout=120,\n    max_active_workflows=8,\n)\n\nasync with application.stream(\n    IncidentRequest(report=\"Checkout returns HTTP 500 since the 14:05 deploy.\"),\n    context=WorkflowContext(workflow_id=\"incident-42\", principal_id=\"team-a\"),\n) as workflow:\n    async for event in workflow:\n        print(event.value.summary)          # each public artifact, as it is published\n    result = await workflow.result()      # always check the terminal outcome\n    result.raise_for_status()\n<\/code><\/pre>\n<p>Leaving the <code>async with<\/code> block while the workflow still runs cancels it and waits for its teardown, so a disconnected client never leaves agents calling models in the background.<\/p>\n<p>Nothing in this API depends on a web framework or on Azure. The repository ships a queue worker and a Starlette SSE endpoint in  <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\/tree\/main\/examples\/13-applications\" target=\"_blank\" rel=\"noreferrer noopener\"><code>examples\/13-applications<\/code><\/a>. Foundry is one host among several, and the one this post is about.<\/p>\n<h2 id=\"HostingItOnFoundryWithFlockCoreFoundry\">Hosting it on Foundry with <code>flock-core[foundry]<\/code><\/h2>\n<p> The Foundry integration ships with <code>flock-core<\/code>, the same way the Dapr state store does. The <code>foundry<\/code> extra pulls in Microsoft&#8217;s  <a href=\"https:\/\/pypi.org\/project\/azure-ai-agentserver-responses\/\" target=\"_blank\" rel=\"noreferrer noopener\"><code>azure-ai-agentserver-responses<\/code><\/a>  SDK, and a plain <code>import flock<\/code> never loads any Azure package:<\/p>\n<pre class=\"wp-block-code\"><code>pip install \"flock-core[azure,foundry]\"\n<\/code><\/pre>\n<p>The adapter wraps the application in the official SDK host. This is the complete hosting code:<\/p>\n<pre class=\"wp-block-code\"><code>import os\n\n# At the very top of main.py, before the first `import flock`:\nos.environ.setdefault(\"FLOCK_AUTO_TRACE\", \"false\")  # the Foundry host owns telemetry\n\nfrom flock.integrations.foundry import FoundryResponsesAdapter, IdentityPolicy\n\nhost = FoundryResponsesAdapter(\n    application,\n    history_mode=\"conversation\",\n    input_mapper=lambda turn: IncidentRequest(\n        report=turn.text, history=turn.history_dicts()\n    ),\n    output_mapper=lambda summary: summary.summary,\n    identity=IdentityPolicy(),\n)\n\nif __name__ == \"__main__\":\n    host.run()  # port $PORT or 8088, SIGTERM-aware\n<\/code><\/pre>\n<p>The input mapper turns a Responses turn into the crew&#8217;s typed input. With <code>history_mode=\"conversation\"<\/code>, the turn carries the current text plus the earlier messages of the conversation with their roles, and Foundry keeps storing that history for us. Our mapper passes both into <code>IncidentRequest<\/code>, so <code>triage<\/code> can use the conversation as context; historical inputs are never re-run. The output mapper decides how each public artifact is rendered as an assistant message, here the summary text; without one, the adapter returns the artifact as JSON text. If turns of one conversation must never overlap, also set  <code>history=\"conversation\"<\/code>  on the application: it then runs them strictly one after the other while other conversations stay concurrent.<\/p>\n<p>Each Foundry request maps onto one workflow:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Foundry<\/th>\n<th>Flock<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>response_id<\/code><\/td>\n<td><code>workflow_id<\/code>, one workflow per response<\/td>\n<\/tr>\n<tr>\n<td>conversation id<\/td>\n<td><code>session_id<\/code>, with turns of one conversation run one at a time when the application sets <code>history=\"conversation\"<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>x-agent-user-id<\/code> header<\/td>\n<td><code>principal_id<\/code>, trusted only inside a hosted container<\/td>\n<\/tr>\n<tr>\n<td>platform call id<\/td>\n<td>workflow attributes, forwarded on model calls with <code>foundry_headers()<\/code><\/td>\n<\/tr>\n<tr>\n<td>each public artifact<\/td>\n<td>one assistant message, streamed as soon as it is published<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The SDK host provides HTTP, SSE, background mode, polling and the <code>\/cancel<\/code> endpoint. The adapter maps the workflow outcome onto the protocol: <code>succeeded<\/code> becomes <code>completed<\/code>, <code>cancelled<\/code> becomes <code>cancelled<\/code>, and  <code>failed<\/code>  or <code>timed_out<\/code> become <code>failed<\/code> with a safe error code. Request options the adapter cannot honor, such as <code>tools<\/code>, <code>temperature<\/code> or a structured output format, are rejected with  <code>invalid_prompt<\/code>  before any agent runs. We prefer an explicit error over an option that is silently ignored.<\/p>\n<p><code>IdentityPolicy()<\/code>  is strict by default. Inside a hosted container the Foundry gateway sets <code>x-agent-user-id<\/code>, an opaque per-user key, and the adapter uses it as the workflow&#8217;s principal. Outside Foundry the header is not trusted at all, because any caller could set it, and requests without a user key are rejected instead of falling back to one shared principal. For crews that partition nothing by user, <code>IdentityPolicy(required=False)<\/code> runs such requests with no principal; for local development, <code>IdentityPolicy(local_development=True)<\/code> is an explicit opt-in that refuses to start inside Foundry.<\/p>\n<h2 id=\"ModelAccessWithTheAgentIdentity\">Model access with the agent identity<\/h2>\n<p> Every hosted agent runs as its own Microsoft Entra <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/agents\/concepts\/hosted-agents\" target=\"_blank\" rel=\"noreferrer noopener\">agent identity<\/a>. Microsoft <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/agents\/concepts\/hosted-agent-permissions\" target=\"_blank\" rel=\"noreferrer noopener\">documents<\/a> that this identity can call models through the project endpoint by default, without an additional role assignment, so the crew reaches its model without any API key in the container. We follow the same path as Microsoft&#8217;s own samples and call <code>&lt;project endpoint&gt;\/openai\/v1<\/code> with a token for <code>https:\/\/ai.azure.com\/.default<\/code>:<\/p>\n<pre class=\"wp-block-code\"><code>import os\n\nfrom flock import DSPyEngine, WorkflowContext\nfrom flock.engines.auth.azure import get_default_azure_token_provider\nfrom flock.integrations.foundry import foundry_headers\n\n# One renewable provider per process, shared by every workflow.\nTOKEN_PROVIDER = get_default_azure_token_provider(scopes=(\"https:\/\/ai.azure.com\/.default\",))\n\n\ndef engine(context: WorkflowContext) -&gt; DSPyEngine:\n    return DSPyEngine(\n        model=f\"azure\/{os.environ['AZURE_AI_MODEL_DEPLOYMENT_NAME']}\",\n        max_completion_tokens=4000,\n        max_retries=3,\n        no_output=True,\n        stream=False,\n        lm_kwargs={\n            \"api_base\": os.environ[\"FOUNDRY_PROJECT_ENDPOINT\"],\n            \"api_version\": \"v1\",\n            \"azure_ad_token_provider\": TOKEN_PROVIDER,\n            \"extra_headers\": foundry_headers(context),\n        },\n    )\n<\/code><\/pre>\n<p>In the factory, each agent gets its own engine with <code>.with_engines(engine(context))<\/code>. If your model lives on an account-level Azure OpenAI endpoint instead, keep the default Cognitive Services scope and grant the agent identity the <code>Cognitive Services OpenAI User<\/code> role on that resource; everything else stays the same. We recommend the project endpoint, because it keeps model access inside the project&#8217;s own permission boundary and matches what the Foundry client libraries do. Two lessons from our first deployment shaped this code. Current reasoning deployments reject  <code>max_tokens<\/code>, and LiteLLM cannot tell from a custom deployment name that it is talking to a reasoning model, so the engine now accepts <code>max_completion_tokens<\/code> and sends only that limit. And the token provider must be created once per process: LiteLLM caches its client per provider, so a provider per request means a new credential, a new token and a new client for every request.<\/p>\n<h2 id=\"DeployWithAzd\">Deploy with azd<\/h2>\n<p> The deployable sample in  <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\/tree\/main\/examples\/14-foundry\/incident-triage\" target=\"_blank\" rel=\"noreferrer noopener\"><code>examples\/14-foundry\/incident-triage<\/code><\/a>  follows the layout of the official <a href=\"https:\/\/github.com\/microsoft-foundry\/foundry-samples\" target=\"_blank\" rel=\"noreferrer noopener\">Foundry samples<\/a>: an <code>azure.yaml<\/code> at the top and the agent in its own folder with <code>main.py<\/code>, a <code>Dockerfile<\/code> and a <code>requirements.txt<\/code>. It contains exactly the crew from this post. Before touching Azure, we run it locally. The sample reads two settings of its own: <code>FLOCK_SAMPLE_OFFLINE<\/code> swaps in deterministic engines, so no model is needed, and  <code>FLOCK_FOUNDRY_LOCAL_DEV<\/code>  turns on <code>IdentityPolicy(local_development=True)<\/code>:<\/p>\n<pre class=\"wp-block-code\"><code>pip install -r requirements.txt\nFLOCK_SAMPLE_OFFLINE=1 FLOCK_FOUNDRY_LOCAL_DEV=1 python main.py\n\ncurl localhost:8088\/readiness\ncurl -N localhost:8088\/responses -H 'content-type: application\/json' \\\n  -d '{\"input\": \"Checkout requests are timing out.\", \"stream\": true}'\n<\/code><\/pre>\n<p>The same container answers <code>background: true<\/code> requests, <code>GET \/responses\/{id}<\/code> polling and <code>POST \/responses\/{id}\/cancel<\/code>, because all of that comes from the SDK host. Apart from installing <code>flock-core[azure,foundry]<\/code> from <code>requirements.txt<\/code>, the  <code>Dockerfile<\/code>  is a plain Python container that starts <code>main.py<\/code>. The part of <code>azure.yaml<\/code> that matters is the service definition:<\/p>\n<pre class=\"wp-block-code\"><code>services:\n  flock-incident-triage:\n    host: azure.ai.agent\n    uses:\n      - ai-project\n    project: src\/flock-incident-triage\n    language: python\n    docker:\n      path: Dockerfile\n      remoteBuild: true\n    kind: hosted\n    protocols:\n      - protocol: responses\n        version: 2.0.0\n    env:\n      AZURE_AI_MODEL_DEPLOYMENT_NAME: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}\n      MAX_ACTIVE_WORKFLOWS: '8'\n    container:\n      resources:\n        cpu: '1'\n        memory: 2Gi\n<\/code><\/pre>\n<p>The <code>container.resources<\/code> apply to one session: Foundry <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/agents\/concepts\/hosted-agents\" target=\"_blank\" rel=\"noreferrer noopener\">scales hosted agents per session<\/a>, with a VM-isolated sandbox for each. From there, <code>azd up<\/code> with the <code>azure.ai.agents<\/code> extension provisions the model deployment, builds the image remotely and <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/foundry\/agents\/how-to\/deploy-hosted-agent\" target=\"_blank\" rel=\"noreferrer noopener\">deploys the hosted agent<\/a>.<\/p>\n<p>Calling it works like calling any other hosted agent:<\/p>\n<pre class=\"wp-block-code\"><code>from azure.ai.projects import AIProjectClient\nfrom azure.identity import DefaultAzureCredential\n\nwith (\n    DefaultAzureCredential() as credential,\n    AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=credential) as project,\n    project.get_openai_client(agent_name=\"flock-incident-triage\") as client,\n):\n    for event in client.responses.create(\n        input=\"Checkout returns HTTP 500 since the 14:05 deploy.\", stream=True\n    ):\n        if event.type == \"response.output_item.done\":\n            print(event.item.content[0].text)\n<\/code><\/pre>\n<p>Run the client in its own environment:  <code>azure-ai-projects<\/code>  2.5 and later requires  <code>openai&gt;=3<\/code>, which cannot be installed next to  <code>flock-core<\/code>  today.<\/p>\n<div id=\"attachment_30603\" style=\"width: 2570px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-scaled.webp\"><img decoding=\"async\" aria-describedby=\"caption-attachment-30603\" class=\"lazyload wp-image-30603 size-full\" src=\"https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-scaled.webp\" data-orig-src=\"https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-scaled.webp\" alt=\"Sequence of a streamed Responses call from the client through Microsoft Foundry and the Flock adapter to an isolated workflow\" width=\"2560\" height=\"1664\" title=\"\" srcset=\"data:image\/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%272560%27%20height%3D%271664%27%20viewBox%3D%270%200%202560%201664%27%3E%3Crect%20width%3D%272560%27%20height%3D%271664%27%20fill-opacity%3D%220%22%2F%3E%3C%2Fsvg%3E\" data-srcset=\"https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-200x130.webp 200w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-300x195.webp 300w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-400x260.webp 400w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-600x390.webp 600w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-768x499.webp 768w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-800x520.webp 800w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-1024x666.webp 1024w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-1200x780.webp 1200w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-1536x998.webp 1536w, https:\/\/whiteduck.de\/wp-content\/uploads\/2026\/10\/flock-foundry-sequence-scaled.webp 2560w\" data-sizes=\"auto\" data-orig-sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/a><p id=\"caption-attachment-30603\" class=\"wp-caption-text\">Sequence of a streamed Responses call from the client through Microsoft Foundry and the Flock adapter to an isolated workflow<\/p><\/div>\n<h2 id=\"WhichHostingPathFits\">Which hosting path fits<\/h2>\n<p>With <code>FlockApplication<\/code>, Flock now has three ways to run a crew:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th><code>flock.serve()<\/code><\/th>\n<th><code>FlockApplication<\/code> in your own host<\/th>\n<th>Foundry hosted agent<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Per-request isolation<\/td>\n<td>\ud83d\udd34<\/td>\n<td>\ud83d\udfe2<\/td>\n<td>\ud83d\udfe2<\/td>\n<\/tr>\n<tr>\n<td>Managed infrastructure, identity and scaling<\/td>\n<td>\ud83d\udd34<\/td>\n<td>\ud83d\udfe1<\/td>\n<td>\ud83d\udfe2<\/td>\n<\/tr>\n<tr>\n<td>Live dashboard<\/td>\n<td>\ud83d\udfe2<\/td>\n<td>\ud83d\udd34<\/td>\n<td>\ud83d\udd34<\/td>\n<\/tr>\n<tr>\n<td>Streaming results to the caller<\/td>\n<td>\ud83d\udfe1<\/td>\n<td>\ud83d\udfe2<\/td>\n<td>\ud83d\udfe2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p><code>serve()<\/code> streams to its dashboard, not to API callers, which is why it gets a yellow mark there. Our recommendations follow directly:<\/p>\n<ul>\n<li><strong>Shared workspace:<\/strong> if a team works on one shared blackboard and wants to watch it live, use <code>serve()<\/code>.<\/li>\n<li><strong>Your own platform:<\/strong> if you already run your own API, queue or platform, embed <code>FlockApplication<\/code> in it.<\/li>\n<li><strong>Agent products on Azure:<\/strong> if you want Entra identity, managed scaling and the Foundry governance story out of the box, run the crew as a Foundry hosted agent.<\/li>\n<\/ul>\n<h2 id=\"TryItAndHelpShapeIt\">Try it, and help shape it<\/h2>\n<p> Flock is open source under the <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\/blob\/main\/LICENSE\" target=\"_blank\" rel=\"noreferrer noopener\">MIT license<\/a>, and we build it in the open on GitHub. The sample in  <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\/tree\/main\/examples\/14-foundry\" target=\"_blank\" rel=\"noreferrer noopener\"><code>examples\/14-foundry<\/code><\/a>  runs locally without a model and deploys with <code>azd up<\/code>, and the guides for <a href=\"https:\/\/whiteducksoftware.github.io\/flock\/guides\/applications\/\" target=\"_blank\" rel=\"noreferrer noopener\">applications<\/a> and <a href=\"https:\/\/whiteducksoftware.github.io\/flock\/guides\/foundry\/\" target=\"_blank\" rel=\"noreferrer noopener\">Foundry hosting<\/a> cover every option shown here.<\/p>\n<p>Host your own crew and tell us where it breaks. If you miss a capability (crash recovery and token streaming are the obvious candidates), open an <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\/issues\" target=\"_blank\" rel=\"noreferrer noopener\">issue<\/a> or start a <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\/discussions\" target=\"_blank\" rel=\"noreferrer noopener\">discussion<\/a>. And if you want to follow where Flock goes next, <a href=\"https:\/\/github.com\/whiteducksoftware\/flock\" target=\"_blank\" rel=\"noreferrer noopener\">star the repository<\/a>: what people build with it decides what we build next. If you want to run agent crews like this in your own Azure environment, <a href=\"https:\/\/whiteduck.de\/en\/contact\/\">talk to us<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Flock 0.5.700 adds FlockApplication and a Microsoft Foundry adapter: every Responses request runs as its own isolated blackboard workflow, with streaming, cancellation and model access through the agent identity.<\/p>\n","protected":false},"author":23,"featured_media":29345,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_tribe_events_control_status":"","_tribe_events_control_status_canceled_reason":"","_tribe_events_control_status_postponed_reason":"","_tribe_events_control_online":"","_tribe_events_control_online_url":"","footnotes":""},"categories":[598],"tags":[644,586,612,989,1032,659],"class_list":["post-30639","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-2","tag-agentic-ai-2","tag-ai-2","tag-flock-2","tag-microsoft-foundry-agents-2","tag-multi-agent-systems-2","tag-open-source-2"],"acf":[],"_links":{"self":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/30639","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/users\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/comments?post=30639"}],"version-history":[{"count":1,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/30639\/revisions"}],"predecessor-version":[{"id":30641,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/30639\/revisions\/30641"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/media\/29345"}],"wp:attachment":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/media?parent=30639"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/categories?post=30639"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/tags?post=30639"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}