• The June 2, 2026 Azure Update Drop: What Shipped and Why It Matters

    On June 2, Microsoft pushed out over a hundred Azure updates in one coordinated drop. Two areas dominated: AI agents and databases. Here are the topics worth knowing and why each one is interesting.

    Azure HorizonDB

    HorizonDB is a Postgres-compatible database, in preview since Ignite. Microsoft already has two managed Postgres options, so the reason for a third matters: it uses shared storage with scale-out compute – the same architecture as AWS Aurora and Google AlloyDB – so compute and storage scale separately and there’s no sharding to manage. Microsoft’s existing distributed Postgres (the Citus engine) shards data across nodes, which is harder to run. HorizonDB also has vector search built into the engine using Microsoft’s DiskANN index, so RAG retrieval can run inside the operational database instead of a separate search service. It’s Microsoft’s answer to Aurora and AlloyDB, and a play for the Postgres migrations coming off Oracle.

    Cosmos DB and DocumentDB

    Cosmos DB: per-partition automatic failover, changing partition keys on the NoSQL API, and an all-versions-and-deletes change feed mode all went GA. In preview: distributed transactions, native Azure Backup, a cost estimator, and a relational-to-NoSQL migration assistant. DocumentDB, the Mongo-compatible engine, added instant free-tier clusters and service-managed failover. Changing partition keys and distributed transactions are the notable ones – both were long-standing gaps in Cosmos.

    MCP across the platform

    MCP (Model Context Protocol) showed up as a built-in surface in several services the same day: an MCP Toolkit for Cosmos DB (GA) and DocumentDB (preview), a data-plane MCP server in API Center, MCP servers as knowledge sources in Foundry IQ, and a workspace-wide MCP for Databricks Genie in Copilot Studio. The interesting part is the timing: MCP went from a community pattern to something Azure services ship natively, across several products in one release wave.

    Foundry agent features

    Several agent capabilities went GA: Hosted Agents in the Foundry Agent Service (managed agent hosting) and Voice Live integration. Two new models landed in the catalog, MAI-Image-2.5 and MAI-Transcribe-1.5. Logic Apps can now call Foundry Agents directly, and a new Logic Apps automation SKU targets agent workflows, which puts agents in the low-code integration layer. On governance, Azure Policy now covers the Model Router and Global PTU reservations became region-agnostic, so reserved capacity isn’t tied to one region.

    Azure AI Search

    OneLake catalog integration and a GenAI prompt skill went GA. In preview, Purview sensitivity labels and access auditing now apply to knowledge sources. The Purview integration is the interesting part: it adds data-governance controls to the retrieval layer that RAG apps depend on.

    Speech and Translator

    GA: the LLM Speech API, Speech SDK 1.50, a Unified Text Translation API, and image, PDF, and Office document translation in AI Translator. HD voice HDv2.5 is in preview. The Unified Text Translation API consolidates the translation features under one API.

    Compute and VMs

    New Arm-based Cobalt 200 VM series (Dpsv7, Dplsv7, Epsv7, Mpsv4, Lpsv5) are in development, Azure Linux 4.0 is in preview, and VMSS Flex got automatic OS image upgrades. Cobalt 200 is Microsoft’s own Arm silicon, following AWS Graviton – more of the fleet moving to in-house chips.

    Containers and AKS

    Azure Container Linux is GA on AKS, AKS Fleet Manager now manages Arc-enabled clusters, and App Gateway for Containers added Istio service-mesh integration. The Fleet Manager change extends multi-cluster management to clusters running outside Azure.

    API Management

    Wildcard custom hostnames went GA on Premium v2 and Standard v2. A Unified Model API for multi-model AI apps is in preview, which lets one API front multiple AI models – relevant if you route across models.

    Monitoring

    Simple log alerts and dynamic thresholds for log search alerts went GA, along with OpenTelemetry metrics and visualizations in Azure Monitor for VMs and Arc servers. Simple log alerts are a lower-friction path than the existing log-search alert rules.

    Storage and Files

    A file-share-centric management model (Microsoft.FileShares) for Azure Files went GA. Secure access to Azure Files on macOS with Entra ID is in preview – native Entra-authenticated SMB from a Mac, which previously needed workarounds.


  • Microsoft Agent Framework 1.0, part 2: a Jenkins-gated debate between agents

    This is Part 2 of the Microsoft Agent Framework 1.0 series. Part 1 went from hello-world to local tools to a remote MCP server. The natural next step is the one the docs only hint at: multiple agents talking to each other, with a third agent breaking the tie. A code-review gate is a good shape for this because the cost of a wrong decision is concrete (a broken merge or a blocked PR), and the inputs (a diff, a PR body, a scan report) are easy to feed in.

    I built one. It lives in a small repo called ai-gate. Jenkins runs it as a per-PR Kubernetes Job: the Job opens a debate between a velocity advocate and a caution advocate, a judge issues a verdict in a strict format, the result is posted back to the PR as a comment, and the Job exits 0, 1, or 2. Jenkins gates the deploy stage on that exit code. Everything below is from the real source.

    You need everything from Part 1 plus three deployments on the same Azure OpenAI account. I used gpt-4o-mini for the velocity advocate (cheap, fast), gpt-4o for the caution advocate (better long-form reasoning), and o4-mini for the judge (a reasoning model). The Job also needs a GitHub fine-grained PAT with contents:read and pull_requests:write on the repos you want to gate.

    Each persona is a system prompt. Velocity and caution are nearly mirror images. The judge fixes the output shape so a parser can read the verdict deterministically:

    VELOCITY = """
    SHIP-IT SAM, the velocity
    advocate. Argue the PR
    SHOULD merge.
    
    Rules:
    - Cite evidence from the diff,
    PR body, tests, scans.
    - 4-6 tight sentences.
    - Concede ONLY when CAUTION
    invalidates your case.
    """
    
    CAUTION = """
    HOLD-THE-LINE HOLLY, the
    quality advocate. Argue the
    PR should be BLOCKED.
    
    Rules:
    - Cite evidence from the diff,
    PR body, tests, scans.
    - 4-6 sentences. Be honest.
    - Never manufacture concerns.
    """
    
    JUDGE = """
    JUDGE-CARLA. Read the debate.
    Output STRICTLY:
    
    VERDICT: APPROVE|BLOCK|NEEDS_HUMAN
    CONFIDENCE: 0-100
    SUMMARY:
    
    KEY EVIDENCE FOR APPROVE:
    - <one line>
    
    KEY EVIDENCE FOR BLOCK:
    
    - <one line>
    
    NEXT ACTION:
    <one line>
    
    """
    
    

    Three rounds of velocity-then-caution, each agent seeing the rolling transcript. After the last round the judge gets the full transcript and emits a verdict in the strict format. One round is partisan; two leaves the last rebuttal unanswered; three forces both sides to confront their weakest point, then either concede or double down:

    def make(deploy, instr):
    return ChatClientAgent(
    chat_client=OAI(
    endpoint=ENDPOINT,
    api_key=KEY,
    deployment_name=deploy,
    api_version=VERSION,
    ),
    instructions=instr,
    )
    
    def run_debate(brief):
    v = make(VEL_DEP, VELOCITY)
    c = make(CAU_DEP, CAUTION)
    j = make(JUDGE_DEP, JUDGE)
    
    log = []
    roll = brief + "\n(no turns)\n"
    
    for n in range(1, ROUNDS + 1):
    out = v.run(
    roll +
    f"\nRound {n}. APPROVE."
    ).content
    log.append(("vel", out))
    
    out2 = c.run(
    roll +
    f"\nVEL: {out}\nBLOCK."
    ).content
    log.append(("cau", out2))
    
    roll += (
    f"\n--- round {n} ---"
    f"\nVEL: {out}"
    f"\nCAU: {out2}\n"
    )
    
    j_in = brief + (
    "\nTRANSCRIPT:\n" +
    "\n".join(
    f"### {w}\n{m}"
    for w, m in log
    ) +
    "\nIssue verdict."
    )
    v_out = j.run(j_in).content
    log.append(("judge", v_out))
    return log, v_out
    

    The strict judge format makes parsing a one-liner per field, not an LLM call. Map VERDICT to an exit code: APPROVE=0, BLOCK=1, NEEDS_HUMAN=2. Jenkins gates the deploy stage on that exit code, so APPROVE flows through and anything else stops the build. The whole thing wraps in one Jenkins shared-library function:

    def call(args) {
    def repo = args.repo
    def pr = args.pr
    def base = args.baseSha
    def head = args.headSha
    def slug = repo
    .replaceAll('[/_.]', '-')
    .toLowerCase()
    def sha = head.take(8)
    def name = (
    "ai-gate-${slug}" +
    "-${pr}-${sha}"
    )
    
    sh """
    envsubst  | kubectl apply -f -
    kubectl wait \\
    --for=condition=complete \\
    --timeout=600s \\
    -n ai-gate \\
    job/${name}
    kubectl logs -n ai-gate \\
    job/${name}
    POD=\$(kubectl get pod \\
    -n ai-gate \\
    -l job-name=${name} \\
    -o jsonpath='{.items[0]\\
    .metadata.name}')
    exit \$(kubectl get pod \\
    -n ai-gate \$POD \\
    -o jsonpath='{.status\\
    .containerStatuses[0].state\\
    .terminated.exitCode}')
    """
    }
    

    Drop that in vars/aiCodeGate.groovy in your Jenkins shared library, then any Jenkinsfile can add a stage that calls aiCodeGate(repo: ..., pr: env.CHANGE_ID, baseSha: env.CHANGE_TARGET_SHA, headSha: env.GIT_COMMIT) before its deploy stage.

    Per PR works out to roughly $0.05 to $0.20 depending on diff size, with 3 rounds of two agents plus one judge call over a ~15k-token context. Wall time is 30-90 seconds. The Foundry Hub and Project are deployed, so the next obvious step is swapping the direct Azure OpenAI chat client for a Foundry connection – that’s Part 3.


  • Microsoft Agent Framework 1.0: three runnable Python examples

    Microsoft Agent Framework reached 1.0 GA on May 21, 2026 for both .NET and Python. It consolidates the previous Semantic Kernel and AutoGen SDKs into one supported codebase with a stable API surface and a long-term support commitment.

    To see what zero-to-agent actually looks like against my own Azure OpenAI deployment, I wrote three small Python examples that progressively add capability: a hello-world agent, an agent with local Python tools, and an agent that connects to a remote MCP server. All three are real files I ran.

    You need Python 3.10 or newer, an Azure OpenAI deployment (I used gpt-4o-mini, which is gpt-4.1-mini behind the alias), the endpoint URL and an API key, and pip install agent-framework==1.0 python-dotenv. Drop the credentials in a .env:

    AOAI_ENDPOINT=https://...
    AOAI_DEPLOYMENT=gpt-4o-mini
    AOAI_API_KEY=...
    AOAI_API_VERSION=2024-10-21
    

    The first example is a single agent that takes one prompt and returns one response. No tools, no state, no MCP. If it returns a sentence, the SDK and the deployment are both working:

    import os
    from dotenv import load_dotenv
    from agent_framework import (
        ChatClientAgent,
    )
    from agent_framework.azure import (
        AzureOpenAIChatClient,
    )
    
    load_dotenv()
    E = os.environ
    
    client = AzureOpenAIChatClient(
        endpoint=E["AOAI_ENDPOINT"],
        api_key=E["AOAI_API_KEY"],
        deployment_name=E["AOAI_DEPLOYMENT"],
        api_version=E["AOAI_API_VERSION"],
    )
    
    agent = ChatClientAgent(
        chat_client=client,
        instructions=(
            "Terse release-notes "
            "summarizer. One sentence."
        ),
    )
    
    prompt = (
        "Summarize: Azure VPN P2S "
        "now supports user-group "
        "IP pools, GA 2026-05-21."
    )
    print(agent.run(prompt).content)
    

    Adding a tool is one more parameter. The Annotated[..., "description"] pattern feeds each parameter description into the tool schema the model sees; the function docstring becomes the tool description:

    from typing import Annotated
    
    PRICES = {
        "MSFT": 412.10,
        "TSLA": 178.42,
        "PGEN": 1.23,
    }
    
    def get_price(
        sym: Annotated[
            str, "Ticker, uppercase"
        ],
    ) -> str:
        "Mock price for a ticker."
        p = PRICES.get(sym.upper())
        if p is None:
            return f"unknown {sym}"
        return f"{sym}: ${p:.2f}"
    
    agent = ChatClientAgent(
        chat_client=client,
        instructions=(
            "Portfolio assistant. "
            "Use the tool for prices."
        ),
        tools=[get_price],
    )
    
    q = "MSFT price? PGEN above $1?"
    print(agent.run(q).content)
    

    With two questions in one prompt the agent calls the tool twice and summarizes both results.

    The third example skips local tools entirely and pulls them from a remote MCP server. Agent Framework ships an MCP client, so any compliant server is a tool source with no glue code. The Microsoft Learn MCP server at learn.microsoft.com/api/mcp is public and Streamable-HTTP:

    import asyncio
    from agent_framework.mcp import (
        MCPStreamableHTTPClient,
    )
    
    URL = (
        "https://learn.microsoft.com"
        "/api/mcp"
    )
    
    async def main():
        mcp = MCPStreamableHTTPClient(
            url=URL,
        )
        async with mcp:
            tools = await mcp.list_tools()
            agent = ChatClientAgent(
                chat_client=client,
                instructions=(
                    "MS Learn assistant. "
                    "Use the MCP tools."
                ),
                tools=tools,
            )
            q = (
                "Front Door Standard "
                "vs Premium tiers?"
            )
            r = await agent.run_async(q)
            print(r.content)
    
    asyncio.run(main())
    

    Swap the URL for GitHub’s, Atlassian’s, or your own private one – the rest of the code is unchanged.

    Two gotchas worth knowing: agent-framework==1.0 moved instructions to the ChatClientAgent constructor, so preview code that set it on ChatClientAgentOptions will break. And if a model deployment rejects parallel tool calls, pass parallel_tool_calls=False on the agent constructor.


  • Azure updates: weeks 21-22, 2026

    Azure shipped a batch of updates over the last two weeks. Here are the five worth more than a line.

    Microsoft Agent Framework 1.0 GA

    Microsoft Agent Framework reached 1.0 GA on May 21 for both .NET and Python. The 1.0 release commits Microsoft to a stable API surface with long-term support. Agent Framework consolidates work that was previously split across Semantic Kernel and AutoGen.

    One breaking change from preview to GA: the Instructions setting moved off ChatClientAgentOptions and onto the ChatClientAgent constructor directly.

    Source: Azure update #560982.

    Azure Front Door WebSocket support (public preview)

    Azure Front Door Standard and Premium now support WebSocket connections with no additional configuration. The HTTP handshake is inspected, then the upgraded connection passes through.

    The practical use case is putting Web PubSub, SignalR, or a custom WebSocket workload behind Front Door for global edge presence and WAF inspection at the handshake. Two things to know: WAF rules apply only to the handshake, not to the open connection; and Web PubSub is not on Front Door Premium’s supported Private Link origin list, so a Standard Internal Load Balancer or Application Gateway is needed between Front Door and a private Web PubSub endpoint.

    Source: Azure Front Door WebSocket (Microsoft Learn).

    P2S User Groups and IP address pools (GA)

    Azure VPN Gateway Point-to-Site connections can now assign IP addresses from different pools based on the user’s Entra ID group membership. Prior to this GA, segmenting VPN users by role required parallel gateways or NSG rules keyed off unpredictable IP ranges.

    The mechanism: define User Groups on the gateway, map each group to an address pool, and set a priority for users that match multiple groups. Downstream NSGs can then key off per-group subnets.

    Source: Azure update #564460.

    Entra-only identities with Azure Files (GA)

    Azure Files SMB shares can now authenticate against Microsoft Entra ID alone, without AD DS, Entra Domain Services, or hybrid identity sync.

    For organizations running cloud-only identity, this removes one of the remaining reasons to keep a domain controller running just for file-share access. Hybrid environments still have their own configuration paths.

    Source: Azure update #562359.

    Virtual network flow logs connector with Microsoft Sentinel (GA)

    Azure now offers a native data connector that sends Virtual Network flow logs directly into Microsoft Sentinel. Before this, getting VNet or NSG flow logs into Sentinel for SecOps correlation required a custom ingestion pipeline, typically built on Storage, Event Hub, and a Function App or Logic App.

    For Sentinel deployments that already ingest the other Azure first-party signal sources (Activity Log, Entra ID sign-ins, Defender for Cloud), this adds network-layer telemetry without parallel ingestion infrastructure. Typical detection use cases include lateral movement, anomalous east-west flows, and exfiltration over uncommon ports.

    The connector is GA, not preview.

    Source: Azure update #564689.


  • Running eclipse-mosquitto in an Azure IoT Edge Module

    I was looking to run a MQTT broker on an IoT edge device, allowing devices to communicate locally with each other. The most important thing is to modify the “Container Create Options” so that the container’s port can be seen on the local network. Also I want to use the no auth mosquitto config (it is in development), so I overrode the cmd section.

    With those changes, the device was able to pull the standard docker image “eclipse-mosquitto:latest” and it started running on the local device and the exposed 1883 port was available for local devices

    {
      "NetworkingConfig": {
        "EndpointsConfig": {
          "host": {}
        }
      },
      "ExposedPorts": {
        "1883/tcp": {}
      },
      "HostConfig": {
        "PortBindings": {
          "1883/tcp": [
            {
              "HostPort": "1883"
            }
          ]
        },
        "NetworkMode": "host"
      },
      "Cmd": [
        "/usr/sbin/mosquitto",
        "-c",
        "/mosquitto-no-auth.conf"
      ]
    }
    

  • How to find the Raspberry Pi model

    Note to self:

    How to find the Raspberry Pi Model :

    cat /proc/device-tree/model
    

  • Azure Functions (PowerShell) : Find the current FunctionApp and Function names

    I was writing an Azure Function in PowerShell. I wanted to know the name of the current FunctionApp and the current Function. Since it was a timer triggered function, I couldn’t pass the names. It took me a while to to figure this out. There may be other ways, but this only way I could find it. Again, this is in PowerShell

    if ($ENV:AZURE_FUNCTIONS_ENVIRONMENT  -eq "Development"){
      $CurrentFunctionAppName=$($PSScriptRoot.split("/")[-2])
      $CurrentFunctionName= $($PSScriptRoot.split("/")[-1])
    }
    else {
      $CurrentFunctionAppName=$($ENV:WEBSITE_SITE_NAME)
      $CurrentFunctionName= $($PSScriptRoot.split("/")[-1])
    }
    

    We need a conditional is as the method is different if you are running local vs in azure.


  • Quickly find that new Raspberry Pi’s address

    Saw this the other day, and I wanted to post it, so that I can remember it.

    How to find a Raspberry Pi’s DHCP address:

    arp -na | grep -i "b8:27:eb"