<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ArshTechPro</title>
    <description>The latest articles on DEV Community by ArshTechPro (@arshtechpro).</description>
    <link>https://dev.to/arshtechpro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3258664%2F7a2cc61a-0b4d-4cf8-884e-52f33905cac3.png</url>
      <title>DEV Community: ArshTechPro</title>
      <link>https://dev.to/arshtechpro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arshtechpro"/>
    <language>en</language>
    <item>
      <title>Penpot for Developers: The Open-Source Design Tool That Speaks Your Language</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Mon, 22 Jun 2026 21:58:38 +0000</pubDate>
      <link>https://dev.to/arshtechpro/penpot-for-developers-the-open-source-design-tool-that-speaks-your-language-47p</link>
      <guid>https://dev.to/arshtechpro/penpot-for-developers-the-open-source-design-tool-that-speaks-your-language-47p</guid>
      <description>&lt;p&gt;Most design tools treat developers as an afterthought. You get handed a file, you squint at a spec panel, and you manually translate someone else's pixels into code that drifts out of sync the moment the design changes.&lt;/p&gt;

&lt;p&gt;Penpot is an open-source design and prototyping platform where &lt;strong&gt;design is expressed as actual code&lt;/strong&gt; — SVG, CSS, HTML, and JSON, the same web standards you already ship. No proprietary &lt;code&gt;.fig&lt;/code&gt; lock-in, no "designer dialect" to interpret. It's MPL-2.0 licensed, written largely in Clojure/ClojureScript with a Rust WebAssembly renderer, and at the time of writing sits around 47k stars on GitHub.&lt;/p&gt;

&lt;p&gt;Here's what's actually in it for you as a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Inspect mode gives you real, ready-to-use code
&lt;/h2&gt;

&lt;p&gt;Every design in Penpot has an Inspect tab that exposes the underlying SVG, CSS, and HTML. Because the design &lt;em&gt;is&lt;/em&gt; web standards under the hood, what you copy is what you ship — not an approximation a plugin reverse-engineered. This removes the translation layer that usually causes design-to-implementation drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Layouts that behave like real CSS
&lt;/h2&gt;

&lt;p&gt;Penpot supports native &lt;strong&gt;CSS Grid and Flexbox&lt;/strong&gt; layouts. You design responsive interfaces using the same layout models that exist in the browser, so the structure you see in the canvas maps onto the box model you'll actually write. Less "why doesn't this reflow like the mockup" friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. An MCP server for AI-driven design-to-code
&lt;/h2&gt;

&lt;p&gt;This is the part worth paying attention to in 2026. Penpot ships an official &lt;a href="https://help.penpot.app/mcp/" rel="noopener noreferrer"&gt;MCP (Model Context Protocol) server&lt;/a&gt;, now integrated directly into the main repo under &lt;code&gt;/mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What it enables: any MCP-compatible AI client — Claude Code, Cursor, Claude Desktop, Copilot-style tools — can read and modify your Penpot design files programmatically. Because designs are already structured, machine-readable code, the agent isn't guessing from a screenshot. It works with the real component tree, styles, and tokens.&lt;/p&gt;

&lt;p&gt;The workflows people are building with it include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Translating a board into production-ready semantic HTML and modular CSS, honoring your design tokens&lt;/li&gt;
&lt;li&gt;Generating interactive prototypes from existing designs&lt;/li&gt;
&lt;li&gt;Turning a rough scribble into a component that respects your design system&lt;/li&gt;
&lt;li&gt;Auto-generating design-system documentation from a file&lt;/li&gt;
&lt;li&gt;Code-to-design (not just design-to-code) and design-to-documentation round trips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick start for Claude Code against a local server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add penpot &lt;span class="nt"&gt;-t&lt;/span&gt; http http://localhost:4401/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP core is written in TypeScript for type-safe interaction with the Penpot Plugin API, and supports both a hosted (remote) setup and a self-hosted local setup. One safety note worth repeating: the MCP key is a personal, non-recoverable token — treat it like a password, and start your agent with read-only prompts (list, inspect, analyze) before letting it write changes to a focused page.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Native design tokens as a single source of truth
&lt;/h2&gt;

&lt;p&gt;Penpot has &lt;strong&gt;first-class native Design Tokens&lt;/strong&gt;, plus Components and Variants. Tokens act as one source of truth shared between design and development, which means no manual token exports and no separate plugin to keep your color/spacing/type scales in sync. Combined with the MCP server, your design system can become a direct context source for AI-generated code.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. An open API, plugins, and webhooks
&lt;/h2&gt;

&lt;p&gt;If you want to automate or integrate, Penpot is programmable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plugin system&lt;/strong&gt; with access to the full workspace — read and write designs programmatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open REST API&lt;/strong&gt; accessible via access tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhooks&lt;/strong&gt; to wire Penpot into your existing toolchain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No app-store review process or corporate gatekeeping to extend the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Self-host it anywhere
&lt;/h2&gt;

&lt;p&gt;Penpot is deployment-agnostic. Use the hosted SaaS at design.penpot.app, or run it on your own infrastructure with Docker, Kubernetes, Elestio, and other options. For teams under compliance constraints (healthcare, finance, government), this means your design IP can live entirely on servers you control — no third-party cloud required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a developer might actually care
&lt;/h2&gt;

&lt;p&gt;The short version: Penpot collapses the gap between design and development by refusing to invent its own format. Web-native output, real CSS layouts, native design tokens, an open API, and an MCP server that makes the whole thing AI-actionable add up to a design platform that speaks the languages you already work in — and that you can own end to end.&lt;/p&gt;

&lt;p&gt;Figma still leads on polish, plugin breadth, and prototyping depth, so this isn't a "rip and replace" pitch. But if data ownership, design-code alignment, or AI-in-the-loop workflows matter to you, Penpot is worth a serious look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reference: &lt;a href="https://github.com/penpot/penpot" rel="noopener noreferrer"&gt;https://github.com/penpot/penpot&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>design</category>
      <category>webdev</category>
    </item>
    <item>
      <title>WWDC 2026 - Build Real-Time Apps and Services with gRPC and Swift</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:35:52 +0000</pubDate>
      <link>https://dev.to/arshtechpro/build-real-time-apps-and-services-with-grpc-and-swift-3iao</link>
      <guid>https://dev.to/arshtechpro/build-real-time-apps-and-services-with-grpc-and-swift-3iao</guid>
      <description>&lt;p&gt;If you have ever hand-written networking code to talk to a backend, you know the pain. You read some documentation, design your request and response types, write the URL handling and JSON decoding, and eventually get something that &lt;em&gt;seems&lt;/em&gt; to work. Then the API changes, the docs fall behind, a field gets renamed, and suddenly your app is silently failing in production.&lt;/p&gt;

&lt;p&gt;gRPC removes most of that friction. Instead of treating server communication as a pile of HTTP endpoints and hand-rolled models, gRPC lets you define your API once, in a single contract, and generate the client and server code from it. With the release of &lt;strong&gt;gRPC Swift 2&lt;/strong&gt;, this workflow has become genuinely idiomatic on Apple platforms and Linux, built around &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; and Swift 6 concurrency.&lt;/p&gt;

&lt;p&gt;This article walks through what gRPC is, why it fits real-time apps so well, and how to use it in a Swift project from start to finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is gRPC?
&lt;/h2&gt;

&lt;p&gt;gRPC is a framework for making &lt;strong&gt;remote procedure calls&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The key mental shift is this: with a typical REST API, you think in terms of HTTP, like URLs, verbs such as GET and POST, status codes, and request bodies. With gRPC, you think in terms of &lt;strong&gt;functions with inputs and outputs&lt;/strong&gt;. Calling the server feels like calling a local function, except the work happens on a remote machine.&lt;/p&gt;

&lt;p&gt;A remote procedure call works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client builds a request message.&lt;/li&gt;
&lt;li&gt;It sends that message to the server.&lt;/li&gt;
&lt;li&gt;The server runs the function and produces a response message.&lt;/li&gt;
&lt;li&gt;The response travels back to the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, a function to fetch a race schedule might be called &lt;code&gt;listRaces&lt;/code&gt;. The client calls it with the number of races it wants, and the server returns the list. From the caller's perspective, it looks almost identical to invoking any other Swift method.&lt;/p&gt;

&lt;p&gt;gRPC is not a niche tool. It runs deep inside large-scale infrastructure, including Apple's own services such as Private Cloud Compute, iCloud Keychain, Photos, and SharePlay file sharing, as well as inter-process communication in Apple's open source Containerization framework. The same library you would use in an iOS app is production-grade for backend systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The contract: Protocol Buffers
&lt;/h2&gt;

&lt;p&gt;Most gRPC services describe their API using &lt;strong&gt;Protocol Buffers&lt;/strong&gt;, usually shortened to &lt;strong&gt;Protobuf&lt;/strong&gt;. This is the source of truth for the service. Because it is a neutral, cross-platform format, the same &lt;code&gt;.proto&lt;/code&gt; file can generate a Swift client, a Go server, a Kotlin client, and so on. Everyone agrees on the same contract.&lt;/p&gt;

&lt;p&gt;You define your service and its messages in a &lt;code&gt;.proto&lt;/code&gt; file. Here is a small example for a racing app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"google/protobuf/timestamp.proto"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;SwiftKart&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;ListRaces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListRacesRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListRacesResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListRacesRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListRacesResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;repeated&lt;/span&gt; &lt;span class="n"&gt;Race&lt;/span&gt; &lt;span class="na"&gt;races&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Race&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;championship&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;laps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;google.protobuf.Timestamp&lt;/span&gt; &lt;span class="na"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;service&lt;/code&gt; block declares one or more RPCs. Here, &lt;code&gt;ListRaces&lt;/code&gt; takes a &lt;code&gt;ListRacesRequest&lt;/code&gt; and returns a &lt;code&gt;ListRacesResponse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Every field has a &lt;strong&gt;unique field number&lt;/strong&gt; (the &lt;code&gt;= 1&lt;/code&gt;, &lt;code&gt;= 2&lt;/code&gt;, and so on). These numbers, not the names, are what gets sent on the wire.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;repeated&lt;/code&gt; means a list, so &lt;code&gt;repeated Race races&lt;/code&gt; is the equivalent of an array of races.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Timestamp&lt;/code&gt; is one of Protobuf's "Well-Known Types," which is why it needs an &lt;code&gt;import&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why the field numbers matter
&lt;/h3&gt;

&lt;p&gt;When gRPC sends a message, it serializes it to a compact &lt;strong&gt;binary representation&lt;/strong&gt; and uses the field number rather than the field name to identify each value. The practical result is that a Protobuf message is roughly half the size of the equivalent JSON payload.&lt;/p&gt;

&lt;p&gt;For a mobile app, smaller messages mean less data transferred and faster network calls, which matters most when the connection is poor. The same efficiency pays off in service-to-service communication on the backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up gRPC Swift in your project
&lt;/h2&gt;

&lt;p&gt;gRPC Swift 2 is distributed as a set of packages so you can pull in only what you need. The three you will most commonly use are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;grpc-swift-2&lt;/code&gt;&lt;/strong&gt; provides the core runtime types and abstractions (&lt;code&gt;GRPCCore&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;grpc-swift-nio-transport&lt;/code&gt;&lt;/strong&gt; provides high-performance HTTP/2 networking built on &lt;a href="https://github.com/apple/swift-nio" rel="noopener noreferrer"&gt;SwiftNIO&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;grpc-swift-protobuf&lt;/code&gt;&lt;/strong&gt; provides the build plugin that generates Swift code from your &lt;code&gt;.proto&lt;/code&gt; files, and integrates with SwiftProtobuf.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a Swift package, your dependencies look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// swift-tools-version: 6.0&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;PackageDescription&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SwiftKart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;platforms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;macOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"15.0"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"18.0"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/grpc/grpc-swift-2.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"2.0.0"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/grpc/grpc-swift-nio-transport.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"2.0.0"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/grpc/grpc-swift-protobuf.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"2.0.0"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nv"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executableTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SwiftKart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GRPCCore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"grpc-swift-2"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GRPCNIOTransportHTTP2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"grpc-swift-nio-transport"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GRPCProtobuf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"grpc-swift-protobuf"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GRPCProtobufGenerator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"grpc-swift-protobuf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: gRPC Swift 2 requires Swift 6 and recent deployment targets (macOS 15+, iOS 18+, tvOS 18+, watchOS 11+, visionOS 2+).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Generating the code in Xcode
&lt;/h3&gt;

&lt;p&gt;If you are working in an Xcode app project rather than a pure Swift package, the flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Project Editor&lt;/strong&gt;, go to the &lt;strong&gt;Package Dependencies&lt;/strong&gt; tab, and add &lt;code&gt;grpc-swift-nio-transport&lt;/code&gt; and &lt;code&gt;grpc-swift-protobuf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select your app target, open &lt;strong&gt;Build Phases&lt;/strong&gt;, and expand &lt;strong&gt;Run Build Tool Plug-ins&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;GRPCProtobufGenerator&lt;/strong&gt; plugin.&lt;/li&gt;
&lt;li&gt;Drop your &lt;code&gt;.proto&lt;/code&gt; file and a small JSON config file into the target.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The plugin scans the target for &lt;code&gt;.proto&lt;/code&gt; files and generates the Swift code when you build. The JSON config controls what gets generated. For an app, you typically only need the &lt;strong&gt;messages&lt;/strong&gt; and the &lt;strong&gt;client&lt;/strong&gt;, not the server code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clients"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time you build, Xcode will ask you to trust the plugin. After that, your generated client and message types are available to import.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making your first call
&lt;/h2&gt;

&lt;p&gt;With the code generated, calling the service from a SwiftUI view looks like ordinary async Swift. Here is the shape of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;GRPCCore&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;GRPCNIOTransportHTTP2&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftProtobuf&lt;/span&gt;

&lt;span class="c1"&gt;// Inside a view, using a .task modifier:&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;withGRPCClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;http2NIOPosix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nv"&gt;transportSecurity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plaintext&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SwiftKart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;wrapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;kart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listRaces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;races&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;races&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Race&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request failed: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;withGRPCClient&lt;/code&gt; creates a client configured with a transport. The transport decides &lt;em&gt;how&lt;/em&gt; the bytes move, in this case HTTP/2 over SwiftNIO, connecting to a local server.&lt;/li&gt;
&lt;li&gt;The raw client only knows about the &lt;em&gt;server&lt;/em&gt;, not your specific service. Wrapping it in the generated &lt;code&gt;SwiftKart.Client&lt;/code&gt; gives you the typed &lt;code&gt;listRaces&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.with { $0.limit = 50 }&lt;/code&gt; is the SwiftProtobuf way of building a message and setting its fields.&lt;/li&gt;
&lt;li&gt;The response is mapped into the app's own model types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that is a complete round trip: a typed request out, a typed response back, with no manual URL building or JSON decoding anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reuse the client, do not recreate it
&lt;/h3&gt;

&lt;p&gt;One important detail: do not create a new gRPC client every time a view appears. Each client establishes its own connection, which adds latency. Instead, create a single client and share it, for example through the SwiftUI environment, so connections can be reused across views.&lt;/p&gt;

&lt;p&gt;It is also good practice to disconnect the client when the app moves to the background to free up resources. A small "client manager" object that connects lazily and tears down on &lt;code&gt;scenePhase&lt;/code&gt; changes handles this cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real power: streaming
&lt;/h2&gt;

&lt;p&gt;So far we have looked at a &lt;strong&gt;unary&lt;/strong&gt; RPC, which is a single request and a single response, just like a normal function call. This is where gRPC's standout feature comes in: every RPC can also &lt;strong&gt;stream&lt;/strong&gt; messages. That opens up three more call types beyond unary.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;RPC type&lt;/th&gt;
&lt;th&gt;Client sends&lt;/th&gt;
&lt;th&gt;Server sends&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unary&lt;/td&gt;
&lt;td&gt;one message&lt;/td&gt;
&lt;td&gt;one message&lt;/td&gt;
&lt;td&gt;Fetching a list, a single lookup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server streaming&lt;/td&gt;
&lt;td&gt;one message&lt;/td&gt;
&lt;td&gt;many messages&lt;/td&gt;
&lt;td&gt;Live commentary feed, notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client streaming&lt;/td&gt;
&lt;td&gt;many messages&lt;/td&gt;
&lt;td&gt;one message&lt;/td&gt;
&lt;td&gt;Uploading telemetry, batching events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bidirectional streaming&lt;/td&gt;
&lt;td&gt;many messages&lt;/td&gt;
&lt;td&gt;many messages&lt;/td&gt;
&lt;td&gt;Live, two-way subscriptions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Think about a live kart race:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server streaming&lt;/strong&gt; is a live text commentary feed. The client asks once, the server keeps pushing updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client streaming&lt;/strong&gt; is each kart pushing its telemetry to the server continuously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bidirectional streaming&lt;/strong&gt; is the richest case. The client tells the server which events it cares about and can change that subscription at any time, while the server streams back the matching events.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Defining a streaming RPC
&lt;/h3&gt;

&lt;p&gt;You mark a streaming parameter with the &lt;code&gt;stream&lt;/code&gt; keyword in the &lt;code&gt;.proto&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;SwiftKart&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;ListRaces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListRacesRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListRacesResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;FollowRace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;FollowRaceRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;FollowRaceResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;FollowRaceRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;race_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;repeated&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="na"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;EVENT_TYPE_UNSPECIFIED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;EVENT_TYPE_KART_LOCATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;EVENT_TYPE_STANDINGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;FollowRaceResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;oneof&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;KartLocations&lt;/span&gt; &lt;span class="na"&gt;locations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Standings&lt;/span&gt; &lt;span class="na"&gt;standings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;oneof&lt;/code&gt; is worth calling out: it maps neatly onto a Swift enum with associated values. A &lt;code&gt;FollowRaceResponse&lt;/code&gt; holds &lt;em&gt;either&lt;/em&gt; kart locations &lt;em&gt;or&lt;/em&gt; standings, and you switch over it on the client just like any Swift enum.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consuming a bidirectional stream on the client
&lt;/h3&gt;

&lt;p&gt;A bidirectional RPC gives you two closures: one for writing requests to the server, and one for reading responses. Here is the shape of consuming the live race feed in SwiftUI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SwiftKart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;wrapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;kart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;followRace&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="c1"&gt;// Send a request whenever the user's interests change.&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;showLeaderboard&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;leaderboardStream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FollowRaceRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raceName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Finite Loops"&lt;/span&gt;
                        &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kartLocations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;showLeaderboard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;standings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;onResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="c1"&gt;// Handle each event the server pushes back.&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Stream failed: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two halves run concurrently. As the user toggles the leaderboard on and off, the client writes new request messages updating its subscription, and the server adjusts what it streams back in real time. The &lt;code&gt;handle(response)&lt;/code&gt; helper switches over the &lt;code&gt;oneof&lt;/code&gt; payload and updates the view, drawing kart positions on a map or refreshing the standings.&lt;/p&gt;

&lt;p&gt;This is the core of a real-time experience: a single long-lived connection carrying a live, two-way conversation, with strongly typed messages on both ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the server side
&lt;/h2&gt;

&lt;p&gt;The same &lt;code&gt;.proto&lt;/code&gt; contract generates the server code too. Implementing a service means conforming to a generated protocol, with one method per RPC. For a unary RPC, that is just an async function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;GRPCCore&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;GRPCNIOTransportHTTP2&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SwiftKartService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SwiftKart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;SimpleServiceProtocol&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;listRaces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ListRacesRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ServerContext&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ListRacesResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;races&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;races&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;ListRacesResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;races&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;races&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting the server is a matter of creating one with a transport and the services it should offer, then calling &lt;code&gt;serve()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;GRPCServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;http2NIOPosix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"0.0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;transportSecurity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plaintext&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nv"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;SwiftKartService&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Streaming RPCs on the server look a little different. The request parameter becomes an async sequence of incoming messages, and the response becomes a writer you push messages into. Handling two streams at once is a natural fit for a Swift &lt;strong&gt;task group&lt;/strong&gt;: one task reads the client's evolving subscription, another follows the live race data and writes matching events back. When the request stream ends, you treat that as the signal to cancel the work and stop sending.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to the cloud
&lt;/h2&gt;

&lt;p&gt;Because gRPC Swift runs on Linux, deploying a service is the standard container workflow. Most cloud providers (Google Cloud Run, AWS, Fly.io, and others) follow a similar pattern even if the exact commands differ.&lt;/p&gt;

&lt;p&gt;The typical steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a &lt;code&gt;Containerfile&lt;/code&gt; that builds the server in release mode. Use a &lt;strong&gt;multi-stage build&lt;/strong&gt;: compile with the full &lt;code&gt;swift:latest&lt;/code&gt; image, then copy just the resulting binary into a smaller &lt;code&gt;swift:slim&lt;/code&gt; runtime image. This keeps the final image from carrying the entire Swift toolchain.&lt;/li&gt;
&lt;li&gt;Publish the image to your provider's container registry.&lt;/li&gt;
&lt;li&gt;Create a deployment. Make sure to enable &lt;strong&gt;HTTP/2&lt;/strong&gt;, since gRPC depends on it.&lt;/li&gt;
&lt;li&gt;Update the app to point at the deployed service's DNS name, and switch the transport security from &lt;code&gt;plaintext&lt;/code&gt; to &lt;strong&gt;TLS&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last change on the client is small but essential:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;http2NIOPosix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"your-service.example.run.app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nv"&gt;transportSecurity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tls&lt;/span&gt;   &lt;span class="c1"&gt;// was .plaintext for local development&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With TLS enabled and the host pointed at the cloud, the same app that talked to your Mac now talks to a service available to everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go next
&lt;/h2&gt;

&lt;p&gt;gRPC Swift has plenty built in to take an app from prototype to production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration with other Swift server packages like &lt;strong&gt;Swift OTel&lt;/strong&gt; (for distributed tracing via OpenTelemetry) and &lt;strong&gt;Swift Service Lifecycle&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Advanced connection management, including custom transports, name resolvers, and &lt;strong&gt;client-side load balancing&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A reflection service, health checks, and interceptors via the &lt;code&gt;grpc-swift-extras&lt;/code&gt; package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fastest way to get comfortable is to prototype one slice of your app-to-server communication with gRPC and feel how the generated code removes the boilerplate. From there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Browse the tutorials and examples in the &lt;a href="https://github.com/grpc/grpc-swift-2" rel="noopener noreferrer"&gt;grpc-swift-2 repository&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since the project is open source, you can ask questions, improve docs, or propose features.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>mobile</category>
      <category>swift</category>
      <category>programming</category>
    </item>
    <item>
      <title>NVIDIA SkillSpector: Should You Scan Your AI Agent Skills Before Installing Them?</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sun, 21 Jun 2026 04:29:05 +0000</pubDate>
      <link>https://dev.to/arshtechpro/nvidia-skillspector-should-you-scan-your-ai-agent-skills-before-installing-them-3am7</link>
      <guid>https://dev.to/arshtechpro/nvidia-skillspector-should-you-scan-your-ai-agent-skills-before-installing-them-3am7</guid>
      <description>&lt;p&gt;If you have been using Claude Code, Codex CLI, Gemini CLI, or any agent framework that supports "skills," you have probably installed a few skills from a marketplace or a random GitHub repo without reading every line of code inside them. Most people do. The skill promises to help with PDF generation, data analysis, or some other task, you drop it into your project, and you move on.&lt;/p&gt;

&lt;p&gt;NVIDIA's new open source tool, &lt;a href="https://github.com/NVIDIA/SkillSpector" rel="noopener noreferrer"&gt;SkillSpector&lt;/a&gt;, exists because that habit is riskier than it looks. This article walks through what SkillSpector does, how to set it up, and whether it is worth adding to your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SkillSpector actually does
&lt;/h2&gt;

&lt;p&gt;SkillSpector is a security scanner purpose-built for AI agent skills rather than general source code. It runs a two-stage pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static analysis&lt;/strong&gt; — fast, regex and AST-based pattern matching that looks for dangerous code patterns (&lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;eval&lt;/code&gt;, &lt;code&gt;subprocess&lt;/code&gt;, obfuscated payloads), taint flows from sensitive sources to network or execution sinks, YARA signature matches for known malware/webshell/cryptominer patterns, and dependency checks against the OSV.dev vulnerability database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional LLM semantic analysis&lt;/strong&gt; — a second pass where a language model evaluates context and intent, filters out false positives from the static stage, and explains findings in plain language. The prompt used for this step includes anti-jailbreak protections so a malicious skill cannot talk its way out of being flagged.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The static stage alone covers a wide net (prompt injection, data exfiltration, privilege escalation, supply chain issues, excessive agency, output handling, system prompt leakage, memory poisoning, tool misuse, rogue-agent behavior, trigger abuse, dangerous code execution, taint tracking, and MCP-specific issues like tool poisoning and least-privilege violations). Adding the LLM pass is what pushes precision up meaningfully, since static pattern matching alone tends to over-flag.&lt;/p&gt;

&lt;p&gt;Every scan ends with a risk score from 0–100 and a severity label, so instead of reading a wall of findings you get a clear signal: safe, use caution, or do not install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;p&gt;You do not need an NVIDIA account or any paid API to get value out of this. Here is the fastest path.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Clone and install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/NVIDIA/skillspector.git
&lt;span class="nb"&gt;cd &lt;/span&gt;skillspector

&lt;span class="c"&gt;# Create and activate a virtual environment&lt;/span&gt;
uv venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;span class="c"&gt;# or, without uv:&lt;/span&gt;
&lt;span class="c"&gt;# python3 -m venv .venv &amp;amp;&amp;amp; source .venv/bin/activate&lt;/span&gt;

&lt;span class="c"&gt;# Install&lt;/span&gt;
make &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="c"&gt;# or, if you want to contribute / run tests:&lt;/span&gt;
make install-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project targets Python 3.12+ and is Apache 2.0 licensed, so there is no licensing friction for commercial use.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Run your first scan
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# A local skill folder&lt;/span&gt;
skillspector scan ./my-skill/

&lt;span class="c"&gt;# A single SKILL.md file&lt;/span&gt;
skillspector scan ./SKILL.md

&lt;span class="c"&gt;# A skill hosted on GitHub&lt;/span&gt;
skillspector scan https://github.com/some-user/some-skill

&lt;span class="c"&gt;# A zipped skill package&lt;/span&gt;
skillspector scan ./my-skill.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole entry point. No config file is required for a basic static scan.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Prefer Docker? Skip Python entirely
&lt;/h3&gt;

&lt;p&gt;If you would rather not set up a Python environment, the repo ships a Dockerfile based on the official &lt;code&gt;python:3.12-slim-bookworm&lt;/code&gt; image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;:/scan"&lt;/span&gt; skillspector scan ./my-skill/ &lt;span class="nt"&gt;--no-llm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Turn on LLM-powered analysis (optional but recommended)
&lt;/h3&gt;

&lt;p&gt;Static analysis alone is fast but can be noisy. Adding an LLM pass improves accuracy and gives you readable explanations for each finding. SkillSpector supports three providers out of the box, plus anything OpenAI-compatible (including local models via Ollama or vLLM):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Env var for the key&lt;/th&gt;
&lt;th&gt;Where it runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OPENAI_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;api.openai.com or any compatible endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;api.anthropic.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA build.nvidia.com&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NVIDIA_INFERENCE_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;build.nvidia.com&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example with Anthropic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SKILLSPECTOR_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;anthropic
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ant-...
skillspector scan ./my-skill/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or point it at a local model with no API key at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SKILLSPECTOR_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openai
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ollama
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:11434/v1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SKILLSPECTOR_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;llama3.1:8b
skillspector scan ./my-skill/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you just want the fast static pass without any model calls, add &lt;code&gt;--no-llm&lt;/code&gt; to any command.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Pick an output format that fits your workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;skillspector scan ./my-skill/ &lt;span class="nt"&gt;--format&lt;/span&gt; json &lt;span class="nt"&gt;--output&lt;/span&gt; report.json       &lt;span class="c"&gt;# automation&lt;/span&gt;
skillspector scan ./my-skill/ &lt;span class="nt"&gt;--format&lt;/span&gt; markdown &lt;span class="nt"&gt;--output&lt;/span&gt; report.md     &lt;span class="c"&gt;# review docs&lt;/span&gt;
skillspector scan ./my-skill/ &lt;span class="nt"&gt;--format&lt;/span&gt; sarif &lt;span class="nt"&gt;--output&lt;/span&gt; report.sarif     &lt;span class="c"&gt;# CI/CD and IDE tooling&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SARIF output is worth calling out specifically: it plugs straight into GitHub code scanning, VS Code, and most CI pipelines that already understand SARIF from other security tools, which makes it realistic to wire this into a pull request check rather than running it manually every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Use it from Python directly
&lt;/h3&gt;

&lt;p&gt;If you want to embed scanning inside your own tooling rather than shelling out to the CLI, the workflow is exposed as a LangGraph graph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;skillspector&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/path/to/skill&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;use_llm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Risk Score: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;risk_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Severity: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;risk_severity&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reading the results
&lt;/h2&gt;

&lt;p&gt;Scores map to four bands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0–20 (LOW)&lt;/strong&gt; — Safe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;21–50 (MEDIUM)&lt;/strong&gt; — Caution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;51–80 (HIGH)&lt;/strong&gt; — Do not install&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;81–100 (CRITICAL)&lt;/strong&gt; — Do not install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each finding in the report points to the exact file and line, names the pattern that triggered it, and (when LLM analysis is enabled) explains why it matters in a sentence or two. That last part is what makes the tool usable by people who are not security specialists — you do not need to know what a taint-flow chain is to understand "this code reads your environment variables and sends them to an external server."&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it falls short
&lt;/h2&gt;

&lt;p&gt;The project is upfront about its limitations, and they are worth knowing before you rely on it as your only line of defense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is static analysis at its core, so it does not execute the skill to observe runtime behavior.&lt;/li&gt;
&lt;li&gt;Non-English content can slip past pattern matching.&lt;/li&gt;
&lt;li&gt;Anything hidden inside an image cannot be inspected.&lt;/li&gt;
&lt;li&gt;Encrypted or compiled code is opaque to the scanner.&lt;/li&gt;
&lt;li&gt;The live CVE lookup (via OSV.dev) needs outbound network access; offline environments fall back to a much smaller built-in list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is unusual for a static scanner, but it means SkillSpector is a strong filter, not a guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  What others are saying
&lt;/h2&gt;

&lt;p&gt;This tool has been getting attention quickly since release. Developer Jacob Bennett, writing on his blog, described the gap NVIDIA addressed as a significant security blind spot for agent skills, and suggested the scanner is a good candidate to wire into CI for organizations that share skills internally. That lines up with how the tool is actually designed to be used: not as a one-time check, but as a recurring gate before a skill gets trusted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it worth a try?
&lt;/h2&gt;

&lt;p&gt;For a few specific situations, yes, clearly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You install skills from public marketplaces or random repos and have never audited what is inside them.&lt;/li&gt;
&lt;li&gt;Your team shares internal skills and you want a lightweight gate before something gets merged or distributed.&lt;/li&gt;
&lt;li&gt;You already use SARIF-based scanning in CI and want this to slot in alongside your existing security tooling.&lt;/li&gt;
&lt;li&gt;You want a quick second opinion before running a skill that asks for broad tool access or touches credentials.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The setup cost is low. A static scan needs nothing beyond a Python virtual environment, runs in seconds, and requires no API keys. Adding the LLM pass takes one extra environment variable and a key for whichever provider you already use, including a fully local option through Ollama if you would rather not send any code to an external API. The license is permissive, the CLI is simple enough to run once and forget, and the output formats mean it fits into an existing pipeline instead of becoming a new manual chore.&lt;/p&gt;

&lt;p&gt;The honest caveat is that this is a young project (the GitHub repository is only a few weeks old at the time of writing), so expect the pattern set and accuracy to keep evolving. It is also not a replacement for actually reading a skill's code if it is going to run with elevated privileges. But as a first-pass filter that takes a few minutes to set up and catches a meaningful share of real issues, it is a reasonable addition to any workflow where you are installing code you did not write and trusting it with system access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick reference
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/NVIDIA/skillspector.git
&lt;span class="nb"&gt;cd &lt;/span&gt;skillspector
uv venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
make &lt;span class="nb"&gt;install

&lt;/span&gt;skillspector scan ./my-skill/ &lt;span class="nt"&gt;--no-llm&lt;/span&gt;        &lt;span class="c"&gt;# fast static check&lt;/span&gt;
skillspector patterns                          &lt;span class="c"&gt;# list all 64 detection patterns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try it on a skill you already have installed, it might be worth checking what comes back before you run that skill again.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
      <category>programming</category>
    </item>
    <item>
      <title>Turso: A Rust Rewrite of SQLite. Setup Guide and Whether It's Worth Your Time</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sun, 21 Jun 2026 04:24:46 +0000</pubDate>
      <link>https://dev.to/arshtechpro/turso-a-rust-rewrite-of-sqlite-setup-guide-and-whether-its-worth-your-time-16lk</link>
      <guid>https://dev.to/arshtechpro/turso-a-rust-rewrite-of-sqlite-setup-guide-and-whether-its-worth-your-time-16lk</guid>
      <description>&lt;p&gt;If you have spent any time in the SQLite-adjacent corner of GitHub lately, you have probably seen the name Turso pop up. The project Turso describes itself as an in-process SQL database written in Rust that is compatible with SQLite. &lt;/p&gt;

&lt;p&gt;This post walks through what the project actually is, how to get it running locally and in the cloud, and an honest take on whether you should bother adopting it right now.&lt;/p&gt;

&lt;h3&gt;
  
  
  First, clear up the naming confusion
&lt;/h3&gt;

&lt;p&gt;Before touching any code, it helps to know there are three related but different things, and mixing them up is the most common source of confusion in the community:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;libSQL&lt;/strong&gt;: Turso's original project, a fork of SQLite written in C. It is production ready today and currently powers Turso Cloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turso (the database engine)&lt;/strong&gt;: The project at the GitHub link above. A clean-room rewrite of SQLite in Rust, started as a side project called "Limbo." It is currently in beta and is explicitly positioned as the successor to libSQL, not a side experiment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turso Cloud&lt;/strong&gt;: The managed, hosted database-as-a-service product built by the same company. It currently runs on libSQL, with the Rust engine gradually being rolled into it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you just want a managed SQLite-compatible database in production today, libSQL plus Turso Cloud is the safer starting point. If you want to try the next-generation engine itself, that is the &lt;code&gt;tursodatabase/turso&lt;/code&gt; repo this article focuses on.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's actually in it for developers
&lt;/h3&gt;

&lt;p&gt;This is the part most setup tutorials skip, so here is the practical pitch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It still talks SQLite.&lt;/strong&gt; Same SQL dialect, same file format, same C API surface where practical. If you know SQLite, you already mostly know Turso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent writes.&lt;/strong&gt; SQLite's biggest historical complaint is its single-writer lock. Turso ships an experimental MVCC engine with &lt;code&gt;BEGIN CONCURRENT&lt;/code&gt;, letting multiple writers commit without blocking each other on simple cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async by design.&lt;/strong&gt; The engine is built around asynchronous I/O (including Linux io_uring), instead of bolting async behavior on top of a synchronous core the way most SQLite drivers have to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native vector search.&lt;/strong&gt; Built-in approximate vector search for embeddings and RAG-style workloads, no extension required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change Data Capture (CDC).&lt;/strong&gt; Real-time tracking of every change made to the database, which is the backbone of Turso's newer sync story.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full-text search&lt;/strong&gt;, powered by the tantivy library, again without an extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption at rest&lt;/strong&gt; and &lt;strong&gt;incremental view maintenance&lt;/strong&gt; (via DBSP), both still marked experimental.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-language support out of the box&lt;/strong&gt;: official packages for Rust, JavaScript/TypeScript, Python, Go, with more community drivers (PHP/Laravel, .NET) appearing in the ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A genuinely open contribution model.&lt;/strong&gt; Unlike SQLite's core, which uses a closed test suite, Turso is built with public deterministic simulation testing and fuzzing against SQLite's own bytecode output, specifically so outside contributors can verify their changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: if you have ever wanted SQLite with safer memory handling, real concurrent writes, and vector search baked in, this project is aimed squarely at you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting it up locally
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Install the CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-LsSf&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://github.com/tursodatabase/turso/releases/latest/download/turso_cli-installer.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows users can use the PowerShell installer linked from the releases page instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Launch the shell&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tursodb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This drops you into an interactive shell connected to a transient in-memory database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;turso&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;turso&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'alice'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;turso&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'bob'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;turso&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;.open FILENAME&lt;/code&gt; inside the shell if you want a persistent file instead of an in-memory database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Prefer Docker or building from source?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# build and run the dev version&lt;/span&gt;
cargo run

&lt;span class="c"&gt;# or with Docker&lt;/span&gt;
make docker-cli-build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make docker-cli-run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Pick a language binding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rust:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add turso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sqlite.db"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="nf"&gt;.connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="nf"&gt;.query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JavaScript/TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @tursodatabase/database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tursodatabase/database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqlite.db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv pip &lt;span class="nb"&gt;install &lt;/span&gt;pyturso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;turso&lt;/span&gt;
&lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqlite.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get turso.tech/database/tursogo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"turso"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sqlite.db"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire local setup. No server, no daemon, no config file: it runs in-process exactly like SQLite always has.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up sync to the cloud
&lt;/h3&gt;

&lt;p&gt;If you want a local-first app that stays in sync with a remote primary, Turso's newer sync package is the relevant piece:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @tursodatabase/sync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tursodatabase/sync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./my-app.db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;libsql://your-db.turso.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need a Turso Cloud database and auth token for the &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;authToken&lt;/code&gt; fields, both available through the &lt;code&gt;turso&lt;/code&gt; CLI or the Turso dashboard. This sync layer is what replaces libSQL's older "embedded replicas" feature, and the project's own team now recommends it over the legacy approach for any new sync work, citing faster replica bootstrap and lower bandwidth use thanks to the async, page-level sync protocol.&lt;/p&gt;

&lt;h3&gt;
  
  
  The honest caveats
&lt;/h3&gt;

&lt;p&gt;The repository itself is upfront about this, and it is worth repeating rather than glossing over: this software is in beta. The maintainers explicitly warn that it may contain bugs and unexpected behavior, and they recommend caution with production data and proper backups.&lt;/p&gt;

&lt;p&gt;A few specifics worth knowing before you commit to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MVCC has real limitations today.&lt;/strong&gt; Indexes cannot currently be created on MVCC-enabled databases, and the entire dataset is eagerly loaded into memory on first access, so very large databases can be slow to start and memory-hungry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query result ordering isn't guaranteed to match SQLite&lt;/strong&gt; in every case, which can matter if your tests or application logic implicitly depend on row order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Several headline features are explicitly experimental&lt;/strong&gt;: encryption at rest, incremental computation, and multi-process WAL coordination all carry that label in the project's own documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;libSQL is still the production recommendation for most things.&lt;/strong&gt; The maintainers say plainly that libSQL is production ready while the Rust engine is not, even though it is evolving quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a knock against the project. It is a young, fast-moving rewrite being built in the open, with public fuzzing against SQLite's own bytecode output as a compatibility check. That is a genuinely rigorous approach. It just means "beta" is not a formality here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it worth a try?
&lt;/h3&gt;

&lt;p&gt;For side projects, prototypes, and anything where you can tolerate some rough edges, yes, it is worth trying. The setup cost is close to zero: one shell script, no servers, and your existing SQLite knowledge mostly transfers directly. If your workload involves frequent concurrent writes, embeddings and vector search, or you simply want to watch where SQLite is heading next, this is a good time to kick the tires.&lt;/p&gt;

&lt;p&gt;A reasonable way to think about it: Turso is not trying to be "yet another database." It is trying to answer a fairly specific question, whether SQLite's simplicity can be carried forward into a memory-safe, async-native, concurrent-write world without losing what made SQLite SQLite.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sql</category>
      <category>database</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop Making Your AI Coding Agent Grep Your Whole Repo — Try codebase-memory-mcp</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sat, 20 Jun 2026 22:01:23 +0000</pubDate>
      <link>https://dev.to/arshtechpro/stop-making-your-ai-coding-agent-grep-your-whole-repo-try-codebase-memory-mcp-4g8l</link>
      <guid>https://dev.to/arshtechpro/stop-making-your-ai-coding-agent-grep-your-whole-repo-try-codebase-memory-mcp-4g8l</guid>
      <description>&lt;p&gt;If you use an AI coding agent — Claude Code, Codex CLI, Gemini CLI, Cursor, Zed, Aider, whatever — you've probably watched it burn through tens of thousands of tokens just trying to figure out who calls a function or where a route is defined. It greps, it reads files, it greps again, it reads more files. Eventually it answers your question, but it took a small forest of tokens and several tool calls to do it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/DeusData/codebase-memory-mcp" rel="noopener noreferrer"&gt;codebase-memory-mcp&lt;/a&gt; is an open-source MCP server built to fix exactly that. It indexes your codebase into a persistent knowledge graph — functions, classes, call chains, HTTP routes, cross-service links — and lets your agent ask structural questions directly instead of reading its way through the filesystem.&lt;/p&gt;

&lt;p&gt;Here's what's actually in it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pitch in one paragraph
&lt;/h2&gt;

&lt;p&gt;You install a single static binary. You tell your agent "index this project." A few seconds to a few minutes later (yes, even the Linux kernel — 28 million lines of code — takes about 3 minutes), your agent can ask things like "what calls &lt;code&gt;ProcessOrder&lt;/code&gt;?" or "show me the architecture of this service" and get an answer in under a millisecond, instead of grepping and reading dozens of files. No Docker, no API keys, no separate database to run. It's just a binary that talks MCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters: the token math
&lt;/h2&gt;

&lt;p&gt;This is the number that should get your attention. According to the project's own benchmarks, five typical structural queries cost roughly 3,400 tokens through codebase-memory-mcp, versus about 412,000 tokens doing the equivalent file-by-file grep-and-read exploration. That's a 99 percent reduction. Less context burned on exploration means more budget left for the agent to actually reason about your problem — and a noticeably faster, cheaper session.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;At its core, codebase-memory-mcp is a structural analysis backend, not another LLM wrapper. It parses your code with tree-sitter, builds a graph of how everything connects, and exposes that graph through 14 MCP tools. Your agent is still the brain — it just stops having to rediscover your codebase from scratch every session.&lt;/p&gt;

&lt;p&gt;A typical interaction looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "what calls ProcessOrder?"
Agent calls: trace_call_path(function_name="ProcessOrder", direction="inbound")
codebase-memory-mcp: executes the graph query, returns structured results
Agent: presents the call chain in plain English
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No extra LLM, no extra API key, no extra cost layer — the agent you're already paying for does the translation from natural language to graph query.&lt;/p&gt;

&lt;h2&gt;
  
  
  The features that actually matter day to day
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It's fast, even on huge repos.&lt;/strong&gt; RAM-first indexing pipeline (LZ4 compression, in-memory SQLite, single dump at the end). Benchmarked on an Apple M3 Pro, the Linux kernel indexes in about 3 minutes; a mid-sized project like Django takes around 6 seconds. Memory is released back to the OS once indexing finishes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It speaks 155 languages.&lt;/strong&gt; Tree-sitter grammars for all of them are vendored directly into the binary, so there's nothing extra to install. Go, C, C++, and the TypeScript/JavaScript/JSX/TSX family additionally get LSP-style hybrid type resolution — proper parameter binding, return-type inference, generic substitution, and JSDoc inference for plain JS files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It plugs into 11 coding agents automatically.&lt;/strong&gt; Running the installer auto-detects Claude Code, Codex CLI, Gemini CLI, Zed, OpenCode, Antigravity, Aider, KiloCode, VS Code, OpenClaw, and Kiro, and configures MCP entries, instruction files, and hooks for whichever ones you have installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It understands more than just application code.&lt;/strong&gt; Dockerfiles, Kubernetes manifests, and Kustomize overlays get indexed as graph nodes too, with cross-references between them — useful if your agent needs to reason about infrastructure as well as application logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It finds dead code, traces blast radius, and detects near-duplicates.&lt;/strong&gt; Beyond simple search, there's Louvain community detection for discovering functional modules, git-diff impact mapping that classifies risk for uncommitted changes, dead code detection (excluding entry points), and MinHash-based near-clone detection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It can visualize the graph.&lt;/strong&gt; An optional UI binary variant ships a built-in 3D graph visualization you can open in a browser at &lt;code&gt;localhost:9749&lt;/code&gt;, running alongside the MCP server as a background thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your team doesn't all have to reindex separately.&lt;/strong&gt; A &lt;code&gt;.codebase-memory/graph.db.zst&lt;/code&gt; artifact can be committed alongside your source — a zstd-compressed snapshot of the graph. When a teammate clones the repo and runs the indexer for the first time, it imports that snapshot and only does an incremental diff locally, instead of a full reindex. It's entirely optional and gitignore-friendly if you'd rather everyone start fresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;The one-line install on macOS or Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;-s -- --ui&lt;/code&gt; on the end if you want the graph visualization included.&lt;/p&gt;

&lt;p&gt;On Windows, download &lt;code&gt;install.ps1&lt;/code&gt; and run it from PowerShell. There's also a manual route if you'd rather inspect everything first: download the platform-specific archive from the &lt;a href="https://github.com/DeusData/codebase-memory-mcp/releases/latest" rel="noopener noreferrer"&gt;latest release&lt;/a&gt;, extract it, and run the bundled install script.&lt;/p&gt;

&lt;p&gt;Once installed, restart your coding agent and just say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Index this project"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the entire setup. If you want indexing to happen automatically whenever you open a new project, turn on auto-index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codebase-memory-mcp config &lt;span class="nb"&gt;set &lt;/span&gt;auto_index &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the initial index, a background watcher keeps the graph in sync with your git changes, so you're not manually re-indexing every time you commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get to ask it
&lt;/h2&gt;

&lt;p&gt;Once a project is indexed, here's a sample of what's available through the 14 MCP tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;search_graph&lt;/code&gt; — structured search by label, name pattern, file pattern, or degree filters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;trace_call_path&lt;/code&gt; — BFS traversal showing what calls a function and what it calls, up to depth 5&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_architecture&lt;/code&gt; — a one-call overview of languages, packages, entry points, routes, hotspots, and clusters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;detect_changes&lt;/code&gt; — maps your current git diff to the symbols it affects, with risk classification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;query_graph&lt;/code&gt; — Cypher-like queries, e.g. &lt;code&gt;MATCH (f:Function)-[:CALLS]-&amp;gt;(g) WHERE f.name = 'main' RETURN g.name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;semantic_query&lt;/code&gt; — vector search over the whole graph using bundled embeddings, no API key required&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;manage_adr&lt;/code&gt; — CRUD operations for Architecture Decision Records, so design decisions persist across sessions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_code_snippet&lt;/code&gt;, &lt;code&gt;search_code&lt;/code&gt;, &lt;code&gt;ingest_traces&lt;/code&gt;, and several more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is also callable directly from the command line if you want to script against it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codebase-memory-mcp cli search_graph &lt;span class="s1"&gt;'{"name_pattern": ".*Handler.*", "label": "Function"}'&lt;/span&gt;
codebase-memory-mcp cli trace_call_path &lt;span class="s1"&gt;'{"function_name": "Search", "direction": "both"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  On trust and security
&lt;/h2&gt;

&lt;p&gt;Reasonable question to ask of any tool that reads your entire codebase: every release binary is scanned by 70+ antivirus engines on VirusTotal before publishing, carries SLSA Level 3 build provenance you can verify with &lt;code&gt;gh attestation verify&lt;/code&gt;, is signed with Sigstore cosign, and ships SHA-256 checksums. There are zero runtime dependencies — every library is vendored at compile time, so there's no transitive supply chain to worry about. All processing happens locally; your code doesn't leave your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you use it?
&lt;/h2&gt;

&lt;p&gt;If your agent sessions are eating context on repetitive file exploration, or you work in a large monorepo where "where is this used" is a constant question, this is a low-effort, high-leverage addition to your setup. It's a single binary, the install is one command, and the worst case is you uninstall it and you're back where you started — &lt;code&gt;codebase-memory-mcp uninstall&lt;/code&gt; cleanly removes configs, hooks, and instructions without touching your binary or databases.&lt;/p&gt;

&lt;p&gt;Repo's here if you want to dig in further or check the source before running it: &lt;a href="https://github.com/DeusData/codebase-memory-mcp" rel="noopener noreferrer"&gt;github.com/DeusData/codebase-memory-mcp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>mcp</category>
      <category>programming</category>
    </item>
    <item>
      <title>WWDC 2026 - WidgetKit Foundations: A Practical Guide for Developers</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 18 Jun 2026 21:42:52 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc-2026-widgetkit-foundations-a-practical-guide-for-developers-2o8d</link>
      <guid>https://dev.to/arshtechpro/wwdc-2026-widgetkit-foundations-a-practical-guide-for-developers-2o8d</guid>
      <description>&lt;h2&gt;
  
  
  What makes a widget worth building
&lt;/h2&gt;

&lt;p&gt;Apple frames good widgets around three qualities, and they're worth keeping in your head as design constraints, not just slogans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Glanceable&lt;/strong&gt; — someone should understand it in a fraction of a second. Think Weather showing you just enough of today's forecast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relevant&lt;/strong&gt; — content should match the moment, the place, and the person's patterns. Calendar surfacing your &lt;em&gt;next&lt;/em&gt; event is the canonical example.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalizable&lt;/strong&gt; — it should be configurable with the content that matters to that specific user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three map directly onto the technical decisions you'll make: glanceable drives your view design, relevant drives your timeline strategy, and personalizable drives whether you reach for a configurable (App Intent) widget.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: how a widget actually runs
&lt;/h2&gt;

&lt;p&gt;This is the part most newcomers get wrong, so it's worth being precise.&lt;/p&gt;

&lt;p&gt;Your widgets are delivered to the system from a &lt;strong&gt;widget extension&lt;/strong&gt;, which is a separate process from your app. That separation has a real consequence: your app can't just hand data to the extension in memory. You share data through an &lt;strong&gt;app group&lt;/strong&gt; container — a shared database, or &lt;code&gt;UserDefaults&lt;/code&gt; backed by the group. Wire this up early; it's the thing people forget.&lt;/p&gt;

&lt;p&gt;Whether your app is UIKit or SwiftUI, the widgets themselves are always built in SwiftUI.&lt;/p&gt;

&lt;p&gt;The data flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WidgetKit asks your extension for content.&lt;/li&gt;
&lt;li&gt;That content is a &lt;strong&gt;timeline&lt;/strong&gt; — a series of &lt;strong&gt;timeline entries&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Each entry carries the data needed to render your view at a specific point in time.&lt;/li&gt;
&lt;li&gt;The rendered views are archived, and the system displays each one at its relevant time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key insight hiding in step 4: &lt;strong&gt;your code is not running while the widget is on screen.&lt;/strong&gt; The system renders archived views. This explains a lot of WidgetKit's API design, including why interactive elements use App Intents rather than closures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building your first widget
&lt;/h2&gt;

&lt;p&gt;When you add a widget extension target, Xcode scaffolds most of what you need. The body returns a &lt;code&gt;WidgetConfiguration&lt;/code&gt;, and you pick one of two types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;StaticConfiguration&lt;/code&gt;&lt;/strong&gt; — the widget configures itself. Simplest option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AppIntentConfiguration&lt;/code&gt;&lt;/strong&gt; — the user configures it (more on this below).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a widget that always shows "the book I'm currently reading," static configuration is the right call. It needs three things: a &lt;code&gt;kind&lt;/code&gt; (a unique string identifier), a timeline provider, and a closure that turns an entry into a view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;DailyReadingGoalWidget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DailyReadingGoalWidget"&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;WidgetConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;StaticConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DailyReadingGoalProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;DailyReadingGoalView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="nv"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colorScheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;containerBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things to call out here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You reuse your app's existing SwiftUI views. If your app is already SwiftUI, the view you pass to the closure is often a view you already have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;containerBackground(for: .widget)&lt;/code&gt; is not optional polish.&lt;/strong&gt; It tells the system which view is your background. When someone applies a colored or clear tint to their Home Screen, the system swaps that background for an adaptive glass material. Skip it and your widget will look broken in tinted environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The timeline provider: three states you must handle
&lt;/h2&gt;

&lt;p&gt;Your provider supplies three distinct things, and conflating them is a common bug source:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snapshot&lt;/strong&gt; — a realistic preview shown in the widget gallery. This is your first impression, and crucially, your app may have &lt;em&gt;zero&lt;/em&gt; user data at this point. Don't show an empty shell. Feature representative sample content (the session uses a popular book with a default message) so people can imagine the widget at its best before adding it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Placeholder&lt;/strong&gt; — the stand-in the system shows while your real timeline loads for the first time. It must appear instantly, so &lt;strong&gt;fetching a placeholder is synchronous&lt;/strong&gt; — no disk reads, no network. The clean trick here is SwiftUI's &lt;code&gt;.redacted(reason:)&lt;/code&gt; modifier to render a skeleton version of your real view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timeline entry&lt;/strong&gt; — what your widget shows at a specific moment, now or in the future. Your provider returns a collection of these, and the system renders each at its time. Each entry should carry &lt;em&gt;everything&lt;/em&gt; the view needs (message, progress, title, cover, etc.).&lt;/p&gt;

&lt;h2&gt;
  
  
  Reload policies: keeping content fresh without burning battery
&lt;/h2&gt;

&lt;p&gt;Timelines eventually run out of entries and need refreshing — that's a &lt;strong&gt;reload&lt;/strong&gt;. You declare reload behavior with one of three policies, and choosing correctly is most of the skill here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.atEnd&lt;/code&gt;&lt;/strong&gt; — reload once all entries are exhausted. Use it when there's no single known "refresh at" time but the timeline will run dry. A widget cycling motivational messages at varied times throughout the day fits this: reload when the last entry has been shown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.afterDate&lt;/code&gt;&lt;/strong&gt; — reload at a specific date you name. Use it when you &lt;em&gt;know&lt;/em&gt; the moment things change. A daily schedule that recalculates at end of day is the textbook case: hand the system "today" and "tomorrow," set the reload for end of day, and provide a fresh schedule when you're asked again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.never&lt;/code&gt;&lt;/strong&gt; — the widget won't reload on its own. Use it when automatic reloads make no sense and updates are driven entirely by interaction. You then trigger refreshes explicitly via &lt;code&gt;WidgetCenter&lt;/code&gt;'s reload APIs or a push notification. A log that only changes when the user logs something fits here.&lt;/p&gt;

&lt;p&gt;A few battery-and-budget realities worth internalizing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provide multiple entries whenever possible&lt;/strong&gt; so the system always has something to show.&lt;/li&gt;
&lt;li&gt;WidgetKit gives each widget an &lt;strong&gt;update budget&lt;/strong&gt;, heavily influenced by how often the user actually looks at the widget. Frequent reloads while your app is in the foreground may be throttled.&lt;/li&gt;
&lt;li&gt;A good habit: if your data may have changed, fire one reload &lt;strong&gt;when your app enters the background&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If your content is genuinely ephemeral — a defined start/end, frequent updates, alerting (think live sports) — that's not a widget, that's a &lt;strong&gt;Live Activity&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One widget, many sizes — and a new family
&lt;/h2&gt;

&lt;p&gt;Once your extension and provider are wired up, supporting additional families is mostly view work. You list what you support with &lt;code&gt;.supportedFamilies&lt;/code&gt;, reuse the same provider, and build a SwiftUI view that suits each shape.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;DailyReadingGoalWidget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DailyReadingGoalWidget"&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;WidgetConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;StaticConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DailyReadingGoalProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;DailyReadingGoalView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="nv"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colorScheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;containerBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supportedFamilies&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemMedium&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apple's guidance is to support as many sizes as make sense so people have placement choices — but starting with one or two families is perfectly fine. Notably, the &lt;strong&gt;system extra large portrait&lt;/strong&gt; family (originally introduced on visionOS 26) is now coming to macOS, iOS, and iPadOS, giving large content a lot more room to breathe.&lt;/p&gt;

&lt;p&gt;Also worth knowing: an iOS widget isn't confined to iOS. It can show up on &lt;strong&gt;CarPlay&lt;/strong&gt; and as a &lt;strong&gt;remote widget on macOS&lt;/strong&gt; without extra work — which is exactly why testing across environments matters later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating the widget with your app
&lt;/h2&gt;

&lt;p&gt;A widget is an extension of your app, and there are three levers to tie them together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deep links
&lt;/h3&gt;

&lt;p&gt;By default, tapping a widget opens your app. If the widget shows specific content, send people straight to it with &lt;code&gt;.widgetURL&lt;/code&gt;. Encode whatever you need (here, a book ID) so the app launches directly to the right screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;DailyReadingGoalWidget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DailyReadingGoalWidget"&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;WidgetConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;StaticConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DailyReadingGoalProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;DailyReadingGoalView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="nv"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colorScheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;containerBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;widgetURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"bookclub://reading/&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bookID&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supportedFamilies&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemMedium&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurable widgets
&lt;/h3&gt;

&lt;p&gt;This is where &lt;code&gt;AppIntentConfiguration&lt;/code&gt; earns its place. Let people pick the content the widget tracks — a location for weather, a specific book to log, and so on. Configurable widgets also let users add several copies with different settings (three widgets, three books).&lt;/p&gt;

&lt;p&gt;Apple's practical rules for configuration are good ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask whether content should differ per user before adding configuration at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it fast&lt;/strong&gt; — one or two parameters is usually enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't require configuration up front.&lt;/strong&gt; Provide a sensible default (the most recently read book, for instance) so the widget is useful immediately and tweakable later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're going down this road, the relevant deep dive is &lt;em&gt;Explore enhancements to App Intents&lt;/em&gt; (WWDC23).&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive elements
&lt;/h3&gt;

&lt;p&gt;Buttons and toggles let people act directly from the widget — checking off a task, completing a chapter. Remember the archived-view reality: your code isn't running on screen, so &lt;strong&gt;buttons and toggles take an App Intent&lt;/strong&gt; the system executes on your behalf. Pick the single most important action in your app and surface that one. For the full treatment, see &lt;em&gt;Bring widgets to life&lt;/em&gt; (WWDC23).&lt;/p&gt;

&lt;h2&gt;
  
  
  Adapting to tinted and clear environments (don't skip this)
&lt;/h2&gt;

&lt;p&gt;On iOS the Home Screen can be tinted with a color or set to a clear style. In those modes the system renders your widget through a &lt;strong&gt;glass material&lt;/strong&gt; — tinting your content and replacing your background with adaptive glass. SwiftUI handles most of it (this is also why &lt;code&gt;containerBackground&lt;/code&gt; matters), but you still have to verify.&lt;/p&gt;

&lt;p&gt;The session walks through a real bug: in clear mode, a book cover image rendered as a plain white rectangle because the system couldn't accent it correctly. The fix is to tell the system how that image should render:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BookCoverImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;imageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;widgetAccentedRenderingMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fullColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;.fullColor&lt;/code&gt; keeps the cover art in its original colors even in accented rendering mode. The broader lesson: imagery especially needs an explicit rendering decision, because the system's default accenting can mangle photographic or full-color assets.&lt;/p&gt;

&lt;h2&gt;
  
  
  A testing checklist before you ship
&lt;/h2&gt;

&lt;p&gt;Pulling the session's testing advice into a list you can actually run through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test on real devices in &lt;strong&gt;full color, tinted, and clear&lt;/strong&gt; modes.&lt;/li&gt;
&lt;li&gt;Remember iOS widgets appear as &lt;strong&gt;remote widgets on macOS&lt;/strong&gt; — verify interactions still feel right from a Mac.&lt;/li&gt;
&lt;li&gt;Lean on &lt;strong&gt;SwiftUI previews&lt;/strong&gt;: the Xcode canvas lets you flip through families, color schemes, and rendering modes without leaving the editor.&lt;/li&gt;
&lt;li&gt;Turn on &lt;strong&gt;WidgetKit developer mode&lt;/strong&gt; during testing to lift constraints like reload budgets so you can iterate quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The takeaways
&lt;/h2&gt;

&lt;p&gt;If you remember nothing else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A widget extension is a &lt;strong&gt;separate process&lt;/strong&gt;; share data through an &lt;strong&gt;app group&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Content is a &lt;strong&gt;timeline of entries&lt;/strong&gt;; handle &lt;strong&gt;snapshot, placeholder, and timeline&lt;/strong&gt; distinctly, and keep placeholders synchronous.&lt;/li&gt;
&lt;li&gt;Pick a &lt;strong&gt;reload policy&lt;/strong&gt; that matches reality — &lt;code&gt;.atEnd&lt;/code&gt;, &lt;code&gt;.afterDate&lt;/code&gt;, or &lt;code&gt;.never&lt;/code&gt; — and respect the update budget.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;containerBackground&lt;/code&gt; and &lt;code&gt;widgetAccentedRenderingMode&lt;/code&gt; so the widget survives &lt;strong&gt;tinted and clear&lt;/strong&gt; Home Screens.&lt;/li&gt;
&lt;li&gt;Tie it to your app with &lt;strong&gt;deep links, configuration, and interactive App Intents&lt;/strong&gt; — and test everywhere the widget can appear, including macOS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Widgets remain one of the highest-leverage surfaces you can add to an app: small to build, and a genuine extension of your app's reach across the system. This session is a clean foundation to build on.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>WWDC 2026 - Migrate to Swift Testing: What Actually Means for Your Test Suite</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Tue, 16 Jun 2026 03:42:57 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc-2026-migrate-to-swift-testing-what-actually-means-for-your-test-suite-47il</link>
      <guid>https://dev.to/arshtechpro/wwdc-2026-migrate-to-swift-testing-what-actually-means-for-your-test-suite-47il</guid>
      <description>&lt;p&gt;Swift Testing shipped with Xcode 16 back in 2024.&lt;/p&gt;

&lt;p&gt;Swift Testing was built from the ground up for Swift. That means Swift concurrency is a first-class citizen, test cases run in parallel by default, and the API surface is dramatically smaller than XCTest's forty-plus assertion functions. One macro, &lt;code&gt;#expect&lt;/code&gt;, replaces most of them.&lt;/p&gt;

&lt;p&gt;If you are still on XCTest, you have probably felt the friction: class inheritance for every test suite, function names that must start with &lt;code&gt;test&lt;/code&gt;, assertion messages that tell you what the values were but not where the expression came from. Swift Testing fixes all of this.&lt;/p&gt;

&lt;p&gt;That said, you do not need to migrate everything at once, and WWDC 2026 is emphatic about this.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Migration Strategy: Small Chunks, No Big Bang
&lt;/h2&gt;

&lt;p&gt;The session opens with something refreshing: permission to be slow about this.&lt;/p&gt;

&lt;p&gt;The recommended approach is to leave your existing XCTests where they are and start using Swift Testing only for new tests. Both frameworks can coexist in the same target and even the same file. You do not need a separate test target, and you do not need a migration sprint.&lt;/p&gt;

&lt;p&gt;The one rule: Swift Testing tests cannot live inside &lt;code&gt;XCTestCase&lt;/code&gt; subclasses. Everything else is fair game.&lt;/p&gt;




&lt;h2&gt;
  
  
  Raw Identifiers for Readable Test Names
&lt;/h2&gt;

&lt;p&gt;One small quality-of-life improvement worth knowing about from the start: Swift supports raw identifiers using backticks, and Swift Testing takes full advantage of this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Testing&lt;/span&gt;

&lt;span class="kd"&gt;@testable&lt;/span&gt; &lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;DemoApp&lt;/span&gt;

&lt;span class="kd"&gt;@Test&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kt"&gt;Default&lt;/span&gt; &lt;span class="nv"&gt;climate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tropical&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Coconut"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="cp"&gt;#expect(fruit.climate == .tropical)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more &lt;code&gt;testDefaultClimateTropical&lt;/code&gt; or dealing with camelCase names in test output. The test name is the test name.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interoperability: The Key to Reusing Your Helper Code
&lt;/h2&gt;

&lt;p&gt;This is the main new story in WWDC 2026 and the feature that makes incremental migration actually work.&lt;/p&gt;

&lt;p&gt;The problem: you have test helper functions that wrap &lt;code&gt;XCTFail&lt;/code&gt;. You want to call them from new Swift Testing tests. Previously, this was messy. Now, it works by design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interoperability&lt;/strong&gt; is a feature that lets you safely call API from one test framework inside a test written in the other. So a Swift Testing test can call a helper that internally uses &lt;code&gt;XCTFail&lt;/code&gt;, and XCTest tests can use Swift Testing's &lt;code&gt;Issue.record&lt;/code&gt; and expectation macros.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Interoperability Modes
&lt;/h3&gt;

&lt;p&gt;The session introduces three modes, and understanding them is important for knowing what level of strictness you want:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limited mode&lt;/strong&gt; -- Cross-framework issues from XCTest become warnings, not errors. Tests still pass. This is the default for test plans created before Xcode 27.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complete mode&lt;/strong&gt; -- Those same warnings become errors. The test will fail. This is the default for new projects in Xcode 27.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strict mode&lt;/strong&gt; -- Cross-framework issues from XCTest cause a fatal error and stop the test immediately at the point of the bad call. This is useful when you want to systematically find every place you need to replace XCTest API.&lt;/p&gt;

&lt;p&gt;You can change modes in your Test Plan settings under "Test Execution," or for Swift Package projects using an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SWIFT_TESTING_XCTEST_INTEROP_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;strict swift &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For SPM projects, complete mode requires bumping to &lt;code&gt;swift-tools-version: 6.4&lt;/code&gt; or newer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrating a Helper Function
&lt;/h3&gt;

&lt;p&gt;Here is a typical helper before migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;assertUnique&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;StaticString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;#filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;#line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;uniqueNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;uniqueNames&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;XCTFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Duplicate name: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After migrating to Swift Testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Testing&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;assertUnique&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;sourceLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SourceLocation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;#sourceLocation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;uniqueNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;uniqueNames&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Issue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Duplicate name: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sourceLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sourceLocation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;XCTFail&lt;/code&gt; becomes &lt;code&gt;Issue.record&lt;/code&gt;. The &lt;code&gt;file&lt;/code&gt; and &lt;code&gt;line&lt;/code&gt; parameters become a single &lt;code&gt;SourceLocation&lt;/code&gt; parameter. The helper can now be called cleanly from both Swift Testing tests and existing XCTests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Migration Patterns
&lt;/h2&gt;

&lt;p&gt;The session walks through two patterns that come up in almost every migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skipping Tests
&lt;/h3&gt;

&lt;p&gt;XCTest uses &lt;code&gt;XCTSkipIf&lt;/code&gt;. In Swift Testing, the direct replacement is &lt;code&gt;Test.cancel&lt;/code&gt;, but the preferred approach is a trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;isFall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;// XCTest&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testSwallowFallMigration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;XCTSkipIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isFall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Wrong season for migration"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Swift Testing via Test.cancel (works but not ideal)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testSwallowFallMigration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isFall&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wrong season for migration"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Preferred: use a trait&lt;/span&gt;
&lt;span class="kd"&gt;@Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;if&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isFall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Wrong season for migration"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kt"&gt;Swallow&lt;/span&gt; &lt;span class="n"&gt;fall&lt;/span&gt; &lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving the condition into a trait keeps the test body clean and makes the enablement logic visible at a glance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Halting After Failures
&lt;/h3&gt;

&lt;p&gt;In XCTest, you set &lt;code&gt;continueAfterFailure = false&lt;/code&gt; to stop on the first failure. In Swift Testing, you use &lt;code&gt;#require&lt;/code&gt; instead of &lt;code&gt;#expect&lt;/code&gt; for the assertions where failure should halt the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cp"&gt;#expect(Fruit.banana.climate == .temperate)&lt;/span&gt;

    &lt;span class="c1"&gt;// If this fails, the test stops here&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;#require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;banana&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;Fruit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plantain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// This line is only reached if #require passed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit over XCTest's approach: you get fine-grained control over which expectations are fatal and which are not, rather than a single global flag.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Unlock After Migrating
&lt;/h2&gt;

&lt;p&gt;The second half of the session is about capabilities that simply do not exist in XCTest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameterized Tests
&lt;/h3&gt;

&lt;p&gt;This is one of the most impactful changes for test suites that have grown unwieldy with repetitive test methods.&lt;/p&gt;

&lt;p&gt;Before, you might write a nested loop inside a single test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Test&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kt"&gt;Birds&lt;/span&gt; &lt;span class="n"&gt;flap&lt;/span&gt; &lt;span class="n"&gt;wings&lt;/span&gt; &lt;span class="n"&gt;successfully&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;bird&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kt"&gt;Aviary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;birds&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="nf"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;bird&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flapWings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem: when it fails, you do not know which bird or which count triggered the failure. The whole loop is one test case.&lt;/p&gt;

&lt;p&gt;After converting to a parameterized test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Aviary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;birds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kt"&gt;Birds&lt;/span&gt; &lt;span class="n"&gt;flap&lt;/span&gt; &lt;span class="n"&gt;wings&lt;/span&gt; &lt;span class="n"&gt;successfully&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bird&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bird&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;bird&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flapWings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swift Testing generates a separate test case for every combination of &lt;code&gt;bird&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt;. All cases run in parallel. When something fails, the Test navigator shows you exactly which inputs caused the failure. In the session's demo, the refactored test also finished significantly faster because of parallel execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exit Tests
&lt;/h3&gt;

&lt;p&gt;Exit tests let you write coverage for code that is expected to crash -- &lt;code&gt;preconditionFailure&lt;/code&gt;, &lt;code&gt;fatalError&lt;/code&gt;, and similar calls that have historically been impossible to test without crashing your entire test process.&lt;/p&gt;

&lt;p&gt;Given this code in a &lt;code&gt;Bird&lt;/code&gt; initializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;preconditionFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bird name cannot be empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Test&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kt"&gt;Bird&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;crashes&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;#expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;processExitsWith&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Bird&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swift Testing runs the body of the exit test in a child process. If that process exits with the expected condition, the test passes. The crash is isolated, so it cannot affect any other test. Exit tests are supported on macOS, Linux, FreeBSD, and Windows.&lt;/p&gt;

&lt;p&gt;This finally gives you a way to get code coverage on defensive guards that were previously invisible to your test suite.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Stays in XCTest
&lt;/h2&gt;

&lt;p&gt;The session is clear about what not to migrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI automation tests using &lt;code&gt;XCUIApplication&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Performance tests using &lt;code&gt;XCTMetric&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tests that catch Objective-C exceptions (only Objective-C code can handle these safely)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For everything else, Swift Testing is the better home.&lt;/p&gt;




&lt;h2&gt;
  
  
  Xcode's Migration Assistance
&lt;/h2&gt;

&lt;p&gt;One practical note from the session: Xcode 27's Coding Assistant is aware of the migration documentation and can help formulate a strategy, review your work, and automate parts of the migration. If you are staring at a large test suite and not sure where to start, that is worth exploring.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Summary
&lt;/h2&gt;

&lt;p&gt;The path forward is clear and low-risk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep your existing XCTests where they are. Do not touch them until you are ready.&lt;/li&gt;
&lt;li&gt;Write all new tests using Swift Testing.&lt;/li&gt;
&lt;li&gt;Enable interoperability and start with limited mode. Gradually move to complete or strict as you migrate individual helpers.&lt;/li&gt;
&lt;li&gt;When you update a helper, replace &lt;code&gt;XCTFail&lt;/code&gt; with &lt;code&gt;Issue.record&lt;/code&gt; and update the source location parameter.&lt;/li&gt;
&lt;li&gt;Look for nested loops in your tests -- those are candidates for parameterized tests.&lt;/li&gt;
&lt;li&gt;Add exit tests anywhere you have &lt;code&gt;preconditionFailure&lt;/code&gt; or &lt;code&gt;fatalError&lt;/code&gt; with no coverage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The migration is not a one-time event. It is a gradual shift that Xcode 27 is explicitly designed to support.&lt;/p&gt;




</description>
      <category>ios</category>
      <category>swift</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>WWDC 2026 - What's New in SwiftData: Sectioned Queries, Codable Attributes, and Observers</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Mon, 15 Jun 2026 10:38:35 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc-2026-whats-new-in-swiftdata-sectioned-queries-codable-attributes-and-observers-2ao5</link>
      <guid>https://dev.to/arshtechpro/wwdc-2026-whats-new-in-swiftdata-sectioned-queries-codable-attributes-and-observers-2ao5</guid>
      <description>&lt;p&gt;WWDC 2026's "What's new in SwiftData" session is a tight, practical one. There's no sweeping redesign here, just four targeted additions that fill gaps developers have been working around for a while. If you've ever fought SwiftData to group a list, store a type you don't own, or react to data changes outside a SwiftUI view, this release is for you.&lt;/p&gt;

&lt;p&gt;Here's everything that's new and how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Sectioned fetching with @Query
&lt;/h2&gt;

&lt;p&gt;Grouping a list by some property used to mean fetching everything flat and then partitioning it yourself in the view. Now &lt;code&gt;@Query&lt;/code&gt; does it for you.&lt;/p&gt;

&lt;p&gt;You pass a key path to the new &lt;code&gt;sectionBy:&lt;/code&gt; parameter. The key path starts at the model root and points to the property you want to group on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;TripListView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="kt"&gt;Trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="nv"&gt;sectionBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;trips&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Trip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$selection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_trips&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="kt"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                        &lt;span class="kt"&gt;TripListItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The wrapped value (&lt;code&gt;trips&lt;/code&gt;) is still a plain &lt;code&gt;[Trip]&lt;/code&gt;, so existing code that reads it keeps working unchanged.&lt;/li&gt;
&lt;li&gt;To reach the sections, you use the underscore-prefixed projected value &lt;code&gt;_trips&lt;/code&gt;, which exposes a &lt;code&gt;sections&lt;/code&gt; property.&lt;/li&gt;
&lt;li&gt;Each section has an &lt;code&gt;id&lt;/code&gt; (the value from your &lt;code&gt;sectionBy&lt;/code&gt; key path, in this case the destination string) and is itself a collection of models you can iterate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So adding sections is additive: keep your flat array where you had it, and reach for &lt;code&gt;_trips.sections&lt;/code&gt; only where you actually want the grouping. Sorting still applies across the whole result set, which keeps section ordering predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Storing custom types with @Attribute(.codable)
&lt;/h2&gt;

&lt;p&gt;SwiftData builds a schema by inspecting your models at launch. That works automatically for its supported value types and for anything you mark &lt;code&gt;@Model&lt;/code&gt;. It falls apart the moment you try to persist a class you don't control.&lt;/p&gt;

&lt;p&gt;The session's example is &lt;code&gt;MKMapItem.Identifier&lt;/code&gt; from MapKit. Add it to a model as-is and the app crashes at launch with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Class property within Persisted Struct/Enum is not supported
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason: SwiftData can't inspect a non-&lt;code&gt;@Model&lt;/code&gt; class to generate a schema, and you can't go annotate a type that lives inside MapKit.&lt;/p&gt;

&lt;p&gt;The fix in this release is a new attribute option. If the type conforms to &lt;code&gt;Codable&lt;/code&gt;, mark the property &lt;code&gt;@Attribute(.codable)&lt;/code&gt; and SwiftData stores the encoded representation instead of trying to model it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftData&lt;/span&gt;

&lt;span class="kd"&gt;@Model&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Trip&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Codable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="kd"&gt;@Attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;codable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;mapItemIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MKMapItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is genuinely useful, but treat it as an escape hatch, not a default. The trade-offs matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opaque to SwiftData.&lt;/strong&gt; A codable attribute is stored as a serialized blob, so you can't use it in predicates to filter or in sort descriptors to sort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No migration awareness.&lt;/strong&gt; If the shape of the codable type changes (you add or remove a property), it won't trigger a migration. Your &lt;code&gt;Codable&lt;/code&gt; implementation has to encode and decode in a forward- and backward-compatible way on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule of thumb from the session: use &lt;code&gt;.codable&lt;/code&gt; for types you &lt;em&gt;don't own&lt;/em&gt; (framework or third-party types). For types you define, model them as &lt;code&gt;@Model&lt;/code&gt; or use supported value types so you keep filtering, sorting, indexing, and migrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Observing query results anywhere with ResultsObserver
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@Query&lt;/code&gt; is great, but it only lives inside SwiftUI views. It fetches when the view appears and keeps watching the store, re-rendering when results change. The problem: plenty of code isn't a SwiftUI view. A state object that derives values from your store, or an app with no SwiftUI at all (think a SceneKit game), had no clean equivalent.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ResultsObserver&lt;/code&gt; is that equivalent. It fetches from your store and observes for changes using Swift Observation, and it works anywhere. It supports the same primitives you already know from &lt;code&gt;@Query&lt;/code&gt;: filtering, sorting, and the sectioning above.&lt;/p&gt;

&lt;p&gt;The session uses it to drive a map camera that should always frame all your trips:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Observable&lt;/span&gt; &lt;span class="kd"&gt;@MainActor&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MapCameraController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;resultsObserver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ResultsObserver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Trip&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MapCameraBounds&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservationTracking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ModelContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;resultsObserver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;ResultsObserver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Trip&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withContinuousObservation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;didSet&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculateBounds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;trips&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultsObserver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;calculateBounds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;trips&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Trip&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;MapCameraBounds&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it fits together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You create a &lt;code&gt;ResultsObserver&lt;/code&gt; for the model. No predicate and no section key path here means "give me everything."&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;withContinuousObservation(options: [.didSet])&lt;/code&gt; gives you a callback whenever the results change. Read &lt;code&gt;resultsObserver.results&lt;/code&gt; inside the closure to get the current set.&lt;/li&gt;
&lt;li&gt;The call returns an &lt;code&gt;ObservationTracking.Token&lt;/code&gt;. That token defines the lifetime of the observation, so store it on the object to keep updates flowing for as long as the object lives. Drop the token and observation stops.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the demo, deleting a trip fires the observation, recalculates the bounds, and the map re-frames. The mental model is "&lt;code&gt;@Query&lt;/code&gt;, but for non-view code."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A naming note: the session and Apple's chapter summaries call this &lt;code&gt;ResultsObserver&lt;/code&gt;, while Apple's published sample snippet writes &lt;code&gt;ModelResultsObserver&amp;lt;Trip&amp;gt;&lt;/code&gt;. Check the final SwiftData headers in your SDK for the exact spelling when you adopt it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Reacting to store changes with HistoryObserver
&lt;/h2&gt;

&lt;p&gt;The second observer targets a different problem: syncing and reacting to changes rather than reading current results.&lt;/p&gt;

&lt;p&gt;Quick refresher on SwiftData history. Every time your store is saved, SwiftData records a &lt;em&gt;history transaction&lt;/em&gt; describing what changed, where the change came from (the author), and a token that uniquely identifies it. You fetch newer transactions with &lt;code&gt;ModelContext.fetchHistory&lt;/code&gt;. (The WWDC 2024 session "Track model changes with SwiftData history" covers the foundations.)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HistoryObserver&lt;/code&gt; makes reacting to that history easy. It exposes a single observable property, &lt;code&gt;eventCounter&lt;/code&gt;, which increments whenever new transactions land. You observe the counter, and when it ticks, you fetch and process the new history. You can also filter by model type and by transaction author, which is what makes server sync clean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@SyncActor&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ServerSync&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HistoryObserver&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservationTracking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;HistoryObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;modelContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;modelContainer&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;

        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withContinuousObservation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;didSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="c1"&gt;// Touch eventCounter so Swift Observation tracks it&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eventCounter&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;processChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Use ModelContext.fetchHistory to fetch and upload changes&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filtering by &lt;code&gt;authors: ["App"]&lt;/code&gt; means you only see changes your app made. That's how you avoid replaying server-originated changes back to the server in an infinite loop.&lt;/li&gt;
&lt;li&gt;You must actually read &lt;code&gt;eventCounter&lt;/code&gt; inside the observation closure. Swift Observation only tracks what you touch, so reading the property is what registers the dependency.&lt;/li&gt;
&lt;li&gt;Same lifetime rule as &lt;code&gt;ResultsObserver&lt;/code&gt;: hold onto the &lt;code&gt;ObservationTracking.Token&lt;/code&gt; for as long as you want to keep observing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the tool for keeping a server, an app extension, or any external system in sync with what's happening in your store.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to reach for which
&lt;/h2&gt;

&lt;p&gt;A quick way to keep the two observers straight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;ResultsObserver&lt;/code&gt;&lt;/strong&gt; when you need the current set of models outside a SwiftUI view and want to recompute when they change (state objects, non-SwiftUI apps, derived values).&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;HistoryObserver&lt;/code&gt;&lt;/strong&gt; when you care about the &lt;em&gt;stream of changes&lt;/em&gt; themselves, especially for syncing with something outside your app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside a SwiftUI view, &lt;code&gt;@Query&lt;/code&gt; is still your first choice; the observers are for everywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;This year's SwiftData is about filling gaps rather than reinventing anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sectioned fetching&lt;/strong&gt; moves grouping into &lt;code&gt;@Query&lt;/code&gt; with &lt;code&gt;sectionBy:&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@Attribute(.codable)&lt;/code&gt;&lt;/strong&gt; is an explicit escape hatch for persisting types you don't own, at the cost of querying, sorting, and migration awareness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ResultsObserver&lt;/code&gt;&lt;/strong&gt; brings &lt;code&gt;@Query&lt;/code&gt;-style fetching and observation to non-SwiftUI code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;HistoryObserver&lt;/code&gt;&lt;/strong&gt; gives you a simple, observable signal for reacting to persistent-history changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are flashy, but each removes a real workaround. If you've been dropping into manual fetches or hand-rolled grouping, this release lets you delete some code.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftdata</category>
      <category>ios</category>
      <category>wwdc</category>
    </item>
    <item>
      <title>WWDC 2026 - Apple's new server LLM on Private Cloud Compute: what's in it for developers</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sat, 13 Jun 2026 20:48:40 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc-2026-apples-new-server-llm-on-private-cloud-compute-whats-in-it-for-developers-2edd</link>
      <guid>https://dev.to/arshtechpro/wwdc-2026-apples-new-server-llm-on-private-cloud-compute-whats-in-it-for-developers-2edd</guid>
      <description>&lt;p&gt;Last year Apple gave us an on-device LLM through the Foundation Models framework. This year that on-device model gets better, and Apple adds something many of us asked for: a &lt;strong&gt;larger server model&lt;/strong&gt; you can call directly from your app, running on &lt;strong&gt;Private Cloud Compute (PCC)&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A new &lt;strong&gt;server-class model&lt;/strong&gt; is now reachable from the same Foundation Models API you already use.&lt;/li&gt;
&lt;li&gt;Switching from on-device to server is a &lt;strong&gt;one-line change&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You get a &lt;strong&gt;32K context window&lt;/strong&gt; (vs 4K on-device), &lt;strong&gt;reasoning&lt;/strong&gt; support, and image input.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No API keys, no auth, no token costs to you.&lt;/strong&gt; Requests are metered against the user's iCloud account, with a daily per-user limit.&lt;/li&gt;
&lt;li&gt;Eligible for apps with &lt;strong&gt;fewer than 2M downloads&lt;/strong&gt;. You apply on the developer site.&lt;/li&gt;
&lt;li&gt;It works across platforms, including &lt;strong&gt;watchOS&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why a server model when we already have on-device
&lt;/h2&gt;

&lt;p&gt;The on-device model is great for fast, private, offline tasks, and this year it improved: it now supports &lt;strong&gt;image input&lt;/strong&gt;, follows instructions more reliably, and is better at calling your custom tools.&lt;/p&gt;

&lt;p&gt;But some features just need more headroom. Think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assistants that reason over a large chunk of user input.&lt;/li&gt;
&lt;li&gt;Workflows that make many tool calls and produce large outputs.&lt;/li&gt;
&lt;li&gt;Tasks where a bigger context window and deeper reasoning materially change quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's where PCC comes in. You get a frontier-class model while keeping Apple's privacy posture intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  The privacy and pricing story (the part that's genuinely different)
&lt;/h2&gt;

&lt;p&gt;Most server LLMs mean: provision an account, manage API keys, eat token costs, and ship a privacy policy that accounts for it. PCC removes most of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by design.&lt;/strong&gt; Data is used only for the request and is never stored, and Apple has had this independently verified by researchers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No keys or auth.&lt;/strong&gt; PCC is integrated into the OS and iCloud. Your user just needs a device that supports Apple Intelligence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No token bill for you.&lt;/strong&gt; Each user gets a daily limit tied to their iCloud account. Users on iCloud+ get higher limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off you're accepting: a network connection is required, and there's a per-user daily cap you need to design around (more on that below).&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating it: one line to switch models
&lt;/h2&gt;

&lt;p&gt;If you've used Foundation Models before, prompting the on-device model is three lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FoundationModels&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Summarize this article: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switching to the PCC server model is a single line, you just hand the session a different model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FoundationModels&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PrivateCloudComputeLanguageModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Summarize this article: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the headline ergonomic win. Same unified Swift API, larger model behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured output and tools work identically
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@Generable&lt;/code&gt; structured output and &lt;code&gt;Tool&lt;/code&gt; calling behave the same whether you're on-device or on PCC. You don't rewrite anything to move between them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FoundationModels&lt;/span&gt;

&lt;span class="kd"&gt;@Generable&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ArticleSummary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;oneLineSummary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;keyPoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;FindRelatedArticlesTool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Tool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PrivateCloudComputeLanguageModel&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nv"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;FindRelatedArticlesTool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Summarize this article: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ArticleSummary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Always check availability
&lt;/h3&gt;

&lt;p&gt;PCC, like the on-device model, only runs on Apple Intelligence devices. Check availability and provide a graceful fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FoundationModels&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ArticleSummarizationView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PrivateCloudComputeLanguageModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isAvailable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Show UI for making request&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Fall back&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  On-device vs PCC: how to choose
&lt;/h2&gt;

&lt;p&gt;Both are private. The rest is a set of trade-offs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;On-device&lt;/th&gt;
&lt;th&gt;PCC server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works offline&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (needs connection)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request limits&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Daily per-user limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context size&lt;/td&gt;
&lt;td&gt;4K&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The session's advice is worth repeating: pick the model based on data, not vibes. The updated on-device model may handle more than you'd expect, and it has no request limits. The only way to know is to evaluate your specific feature (Apple's new Evaluations framework, covered in "Meet the Evaluations framework," is built for exactly this).&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasoning levels
&lt;/h2&gt;

&lt;p&gt;PCC supports reasoning, where the model generates extra "thinking" text in a separate transcript segment before producing the final answer. There are three levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.light&lt;/code&gt; gathers a bit of extra context.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.moderate&lt;/code&gt; reasons a little deeper.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.deep&lt;/code&gt; can produce a reasoning segment longer than the answer itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You set it per request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;contextOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ContextOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;reasoningLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Reasoning levels: .light, .moderate, .deep&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things to keep in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning is generated text, so it consumes tokens&lt;/strong&gt; and counts against your context limit.&lt;/li&gt;
&lt;li&gt;The reasoning lives in the session transcript, so you can &lt;strong&gt;observe the transcript to show progress&lt;/strong&gt;. This matters most with &lt;code&gt;.deep&lt;/code&gt;, which can take a while.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Reading context size programmatically
&lt;/h3&gt;

&lt;p&gt;You can now query context size directly instead of hardcoding it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;SystemLanguageModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contextSize&lt;/span&gt;
&lt;span class="c1"&gt;// 4096 on 26.0&lt;/span&gt;
&lt;span class="c1"&gt;// 8192 on 27.0 (newer devices)&lt;/span&gt;

&lt;span class="kt"&gt;PrivateCloudComputeLanguageModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contextSize&lt;/span&gt;
&lt;span class="c1"&gt;// 32768&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling usage limits (don't skip this)
&lt;/h2&gt;

&lt;p&gt;Because requests are metered against the user's iCloud account, your app will eventually hit a user who's at their daily cap. If the only thing that happens is a thrown error surfaced in the UI, that's a poor, non-actionable experience.&lt;/p&gt;

&lt;p&gt;Instead, inspect &lt;code&gt;quotaUsage&lt;/code&gt; and render persistent, actionable UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ArticleSummarizationView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PrivateCloudComputeLanguageModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;belowLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quotaUsage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isApproachingLimit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nearing usage limit."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quotaUsage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isLimitReached&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Usage limit exceeded."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;red&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;suggestion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quotaUsage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limitIncreaseSuggestion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Show options"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;suggestion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design guidance from the session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Avoid alerts.&lt;/strong&gt; Use UI that persists and isn't dismissed, for example a disabled request button with a subtle label beneath it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offer the upgrade path.&lt;/strong&gt; &lt;code&gt;limitIncreaseSuggestion&lt;/code&gt; lets the user manage or raise their limit (such as upgrading their iCloud account).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle the "approaching limit" case too&lt;/strong&gt;, so users can make informed decisions about which requests are worth spending on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing limit states in Xcode
&lt;/h3&gt;

&lt;p&gt;You don't need to burn real quota to test this. In your scheme, go to &lt;strong&gt;Debug &amp;gt; Options&lt;/strong&gt; and use &lt;strong&gt;Simulate Apple Foundation Models Availability&lt;/strong&gt;. You can select &lt;strong&gt;Quota Usage Limit Reached&lt;/strong&gt; and &lt;strong&gt;Nearing Usage Limit&lt;/strong&gt; to exercise both code paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combining on-device and server models
&lt;/h2&gt;

&lt;p&gt;You're not forced to pick one. A common pattern is to route simple work to the on-device model and escalate harder tasks to PCC. The session points to "Build agentic app experiences with Foundation Models" for that workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting access
&lt;/h2&gt;

&lt;p&gt;The server model is available for apps with &lt;strong&gt;fewer than 2M downloads&lt;/strong&gt;, and you &lt;strong&gt;apply on the Apple Developer website&lt;/strong&gt;. If your feature genuinely needs the larger context or reasoning, it's worth applying early.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Summary&lt;br&gt;
If you already use Foundation Models, reaching for a bigger model is now a one-line decision, with privacy handled and no token bill to manage. Evaluate, choose the right tier for each task, and design for the daily limit up front.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ai</category>
      <category>ios</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>WWDC 2026 - What's New in Swift</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 11 Jun 2026 16:04:12 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc-2026-whats-new-in-swift-3nb2</link>
      <guid>https://dev.to/arshtechpro/wwdc-2026-whats-new-in-swift-3nb2</guid>
      <description>&lt;p&gt;Swift 6.3 and 6.4 landed at WWDC 2026 with a strong theme running through them: less boilerplate, fewer surprises, and more control. The session covers four broad areas — language improvements, library updates, cross-platform support, and performance. This article also folds in what shipped in Swift 6.3 earlier this year that the session touched on but did not fully detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better Swift Concurrency diagnostics&lt;/li&gt;
&lt;li&gt;Improved &lt;code&gt;Sendable&lt;/code&gt; conformances — &lt;code&gt;weak let&lt;/code&gt; support, &lt;code&gt;~Sendable&lt;/code&gt; opt-out&lt;/li&gt;
&lt;li&gt;More accessible memberwise initializers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;anyAppleOS&lt;/code&gt; availability shorthand&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@diagnose&lt;/code&gt; for per-declaration warning control&lt;/li&gt;
&lt;li&gt;Module selectors (&lt;code&gt;::&lt;/code&gt; syntax) for disambiguating name conflicts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@c&lt;/code&gt; attribute for exposing Swift functions to C code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Library&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;withTaskCancellationShield&lt;/code&gt; for protecting critical work from cancellation&lt;/li&gt;
&lt;li&gt;Safe &lt;code&gt;Continuation&amp;lt;Success, Failure&amp;gt;&lt;/code&gt; type with compile-time misuse detection&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ref&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;MutableRef&amp;lt;T&amp;gt;&lt;/code&gt; — safe first-class references without unsafe pointers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dictionary.mapKeyedValues&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;FilePath&lt;/code&gt; type in Foundation&lt;/li&gt;
&lt;li&gt;Swift Testing: issue severity, test cancellation, image attachments, and XCTest interoperability&lt;/li&gt;
&lt;li&gt;Subprocess output streaming&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProgressManager&lt;/code&gt; for structured async progress reporting&lt;/li&gt;
&lt;li&gt;DocC: Markdown output, static HTML content, code block annotations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@inline(never)&lt;/code&gt; / &lt;code&gt;@inline(always)&lt;/code&gt; for explicit inlining control&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@specialized&lt;/code&gt; for pre-compiled generic specializations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@export(implementation)&lt;/code&gt; for ABI-stable library optimization&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~Copyable&lt;/code&gt; and &lt;code&gt;~Escapable&lt;/code&gt; in protocol associated types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;borrow&lt;/code&gt; and &lt;code&gt;mutate&lt;/code&gt; accessors for non-copyable types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MutableRef&lt;/code&gt; for hoisting repeated subscript accesses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cross-Platform&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Official Swift SDK for Android&lt;/li&gt;
&lt;li&gt;Embedded Swift improvements&lt;/li&gt;
&lt;li&gt;Swift Build preview in Swift Package Manager&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Language Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Better Swift Concurrency Diagnostics
&lt;/h3&gt;

&lt;p&gt;The compiler now catches more concurrency mistakes and gives you clearer guidance when it does. Two patterns that previously slipped through are now properly diagnosed: catching errors inside a &lt;code&gt;Task&lt;/code&gt; block, and saving a task reference for later rendezvous.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Catching inside a Task&lt;/span&gt;
&lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;lander&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lander&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Saving a Task for later&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;landingTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;lander&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;orbiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rendezvous&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lander&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;orbiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;justHangOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;waitingFor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;landingTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Improved &lt;code&gt;Sendable&lt;/code&gt; Conformances
&lt;/h3&gt;

&lt;p&gt;Working with &lt;code&gt;Sendable&lt;/code&gt; in class hierarchies just got more expressive. You can now mark a class as &lt;code&gt;~Sendable&lt;/code&gt; to opt out, and &lt;code&gt;weak let&lt;/code&gt; properties are supported in &lt;code&gt;Sendable&lt;/code&gt; types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Spacecraft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;dockedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SpaceStation&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="c1"&gt;// weak let now works in Sendable types&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Mission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CrewedMission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;@unchecked&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  More Accessible Memberwise Initializers
&lt;/h3&gt;

&lt;p&gt;Swift now generates multiple memberwise initializers at different access levels based on property visibility. If a struct has a mix of &lt;code&gt;internal&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; properties, you get both an &lt;code&gt;internal&lt;/code&gt; initializer (without the private properties) and a &lt;code&gt;private&lt;/code&gt; one (with everything). No more hand-writing boilerplate initializers just to work around access control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Briefing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="kd"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;scheduledAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt;  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;attendees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Swift generates both:&lt;/span&gt;
&lt;span class="c1"&gt;// internal init(topic:scheduledAt:)&lt;/span&gt;
&lt;span class="c1"&gt;// private  init(topic:scheduledAt:attendees:)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;anyAppleOS&lt;/code&gt; Availability
&lt;/h3&gt;

&lt;p&gt;Tired of spelling out every Apple platform in availability annotations? Swift 6.4 introduces &lt;code&gt;anyAppleOS&lt;/code&gt; as a shorthand that covers iOS, macOS, watchOS, tvOS, and visionOS in one shot. Works in both &lt;code&gt;@available&lt;/code&gt; attributes and &lt;code&gt;#if&lt;/code&gt; conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;@available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;macOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watchOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tvOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;visionOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;showStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;@available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyAppleOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;showStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;#if os(anyAppleOS)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeLiveActivityWidget&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can still layer platform-specific exclusions on top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyAppleOS&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;@available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tvOS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unavailable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;@diagnose&lt;/code&gt; — Fine-Grained Warning Control
&lt;/h3&gt;

&lt;p&gt;The new &lt;code&gt;@diagnose&lt;/code&gt; attribute lets you control how the compiler treats specific diagnostics on a per-declaration basis. You can silence a deprecation warning, promote a warning to an error, or demote a future error to a warning — all scoped to a single function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Silence a deprecation warning with a reason&lt;/span&gt;
&lt;span class="kd"&gt;@diagnose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;DeprecatedDeclaration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Flying with surplus hardware"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeApolloSoyuzMission&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Mission&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Treat strict memory safety as a warning instead of the default&lt;/span&gt;
&lt;span class="kd"&gt;@diagnose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;StrictMemorySafety&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;uplinkCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="kt"&gt;Receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;computer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="kt"&gt;Computer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Treat a future Swift error as an error now, ahead of the version bump&lt;/span&gt;
&lt;span class="kd"&gt;@diagnose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ErrorInFutureSwiftVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;fetchPosition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Module Selectors (&lt;code&gt;::&lt;/code&gt; Syntax)
&lt;/h3&gt;

&lt;p&gt;When two imported modules export the same name, Swift 6.3 gives you a clean way to be explicit: the double-colon module selector. It works on both types and members.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Rocket&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;GiftShopToys&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;rocket2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Rocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;SaturnV&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// ambiguous — prefers Rocket module's Rocket.SaturnV&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;rocket3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Rocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;SaturnV&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// unambiguous — definitely Rocket module's SaturnV&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also resolves method name conflicts from protocol extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Calls the HumanResources version of fire(), not Chemistry's&lt;/span&gt;
&lt;span class="n"&gt;launchPadTechnician&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HumanResources&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Module selectors also work with the &lt;code&gt;Swift&lt;/code&gt; module itself, which is useful when a local name shadows a standard library type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Swift&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// async work&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;@c&lt;/code&gt; Attribute for C Interoperability
&lt;/h3&gt;

&lt;p&gt;Swift 6.3 introduces the &lt;code&gt;@c&lt;/code&gt; attribute, which lets you expose Swift functions and enums to C code. Annotating a function with &lt;code&gt;@c&lt;/code&gt; causes Swift to include a matching declaration in the generated C header — no manual bridging header edits required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@c&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;callFromC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Generated C header:&lt;/span&gt;
&lt;span class="c1"&gt;// void callFromC(void);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can provide a custom name for the generated C declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MyLibrary_callFromC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;callFromC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Generated C header:&lt;/span&gt;
&lt;span class="c1"&gt;// void MyLibrary_callFromC(void);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@c&lt;/code&gt; also pairs with &lt;code&gt;@implementation&lt;/code&gt;, letting you write a Swift implementation for a function that is already declared in a C header. Swift validates that the signatures match rather than generating a new declaration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// C header&lt;/span&gt;
&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;callFromC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Swift implementation&lt;/span&gt;
&lt;span class="kd"&gt;@c&lt;/span&gt; &lt;span class="kd"&gt;@implementation&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;callFromC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Library Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;withTaskCancellationShield&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes a piece of work must complete even if the parent task is cancelled — like sending an emergency signal. The new &lt;code&gt;withTaskCancellationShield&lt;/code&gt; wrapper protects a block of code from task cancellation, letting it run to completion regardless.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;EmergencyTransponder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sendSOS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;withTaskCancellationShield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;radio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;makeSOSPacket&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Safe Continuations with &lt;code&gt;Continuation&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Bridging callback-based APIs to Swift concurrency has always required a tradeoff: &lt;code&gt;UnsafeContinuation&lt;/code&gt; is fast but silent on misuse, while &lt;code&gt;CheckedContinuation&lt;/code&gt; catches mistakes at the cost of extra allocations. Swift 6.3 adds a third option, &lt;code&gt;Continuation&amp;lt;Success, Failure&amp;gt;&lt;/code&gt;, that makes double-resume a compile-time error and a missing resume a runtime trap — with no overhead on the fast path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;withContinuation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;continuation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;someCallbackAPI&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="n"&gt;continuation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;returning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;Ref&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;MutableRef&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Storing a reference to part of a data structure previously required either a class (heap allocation, reference counting) or &lt;code&gt;UnsafePointer&lt;/code&gt; (all the unsafe caveats). Swift 6.3 adds &lt;code&gt;Ref&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;MutableRef&amp;lt;T&amp;gt;&lt;/code&gt; to the standard library: safe types that hold shared and exclusive references to a value respectively, usable as local variables, struct members, and generic type parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Dictionary.mapKeyedValues&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A small but welcome addition. When you need to transform dictionary values while keeping access to the key, you previously had to construct the result manually. Now there is a purpose-built method for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Mission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;uniqueKeysWithValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;missions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;lazy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;launchWindow&lt;/span&gt; &lt;span class="nf"&gt;in&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;makeDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;launchWindow&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="n"&gt;missions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapKeyedValues&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;launchWindow&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="nf"&gt;makeDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;launchWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New &lt;code&gt;FilePath&lt;/code&gt; Type
&lt;/h3&gt;

&lt;p&gt;Foundation gains a new &lt;code&gt;FilePath&lt;/code&gt; type that correctly handles macOS resource forks and named resources (the &lt;code&gt;..namedresource/rsrc&lt;/code&gt; path suffix). When iterating path components, it strips these platform-specific suffixes automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FilePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/var/www/static/..namedresource/rsrc"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// [ "var", "www", "static" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Swift Testing: Issue Severity, Test Cancellation, and Image Attachments
&lt;/h3&gt;

&lt;p&gt;Swift Testing picks up three improvements. First, you can record an issue with a &lt;code&gt;.warning&lt;/code&gt; severity — useful for soft failures that do not warrant stopping the test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Issue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;rocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; remaining fuel is below 10% reserve target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, &lt;code&gt;Test.cancel&lt;/code&gt; lets a test stop itself early with a message, which is cleaner than a conditional &lt;code&gt;return&lt;/code&gt; and more expressive than skipping.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engineType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;solid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;rocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; has solid fuel"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Third, you can now attach images to test results on Apple and Windows platforms via new cross-import overlay modules with UIKit and other UI frameworks. Useful for snapshot-style tests where seeing what was rendered matters as much as whether the assertion passed.&lt;/p&gt;

&lt;h3&gt;
  
  
  XCTest Interoperability
&lt;/h3&gt;

&lt;p&gt;You can now freely mix XCTest assertions and Swift Testing expectations in the same codebase — calling &lt;code&gt;XCTAssertEqual&lt;/code&gt; from a Swift Testing test, or using &lt;code&gt;#expect&lt;/code&gt; inside an &lt;code&gt;XCTestCase&lt;/code&gt;. Migration from XCTest no longer has to be all-or-nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subprocess Output Streaming
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Subprocess&lt;/code&gt; now supports streaming output via &lt;code&gt;.sequence&lt;/code&gt;, so you can process command output lazily as it arrives instead of waiting for the process to finish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="kt"&gt;Subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ls"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                                      &lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;execution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;standardOutput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasSuffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".obj"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;objectFiles&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;closureOutput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Object file: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;objectFiles&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Progress Reporting
&lt;/h3&gt;

&lt;p&gt;A new &lt;code&gt;ProgressManager&lt;/code&gt; API brings structured progress reporting with Swift concurrency support. Progress can be composed hierarchically using subprogress objects, and updates can be observed with &lt;code&gt;Observations&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ProgressManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;totalCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;rocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subprogress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;assigningCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kt"&gt;Observations&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fractionCompleted&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mission &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DocC Improvements
&lt;/h3&gt;

&lt;p&gt;Swift 6.3 adds three experimental capabilities to DocC worth knowing about if you maintain a library:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown output.&lt;/strong&gt; Generate Markdown versions of documentation pages alongside the standard rendered JSON using &lt;code&gt;--enable-experimental-markdown-output&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static HTML content per page.&lt;/strong&gt; Embed a lightweight HTML summary of each page — title, description, availability, declarations — directly in &lt;code&gt;index.html&lt;/code&gt; inside a &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; tag. Improves search engine discoverability and screen reader accessibility without requiring JavaScript. Pass &lt;code&gt;--transform-for-static-hosting --experimental-transform-for-static-hosting-with-content&lt;/code&gt; to enable it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code block annotations.&lt;/strong&gt; New formatting options for fenced code blocks: &lt;code&gt;nocopy&lt;/code&gt; disables the copy-to-clipboard button, &lt;code&gt;highlight&lt;/code&gt; highlights specific line numbers, &lt;code&gt;showLineNumbers&lt;/code&gt; shows line numbers, and &lt;code&gt;wrap&lt;/code&gt; wraps long lines at a column width.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="err"&gt;```&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;              &lt;span class="c1"&gt;// highlighted&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// highlighted&lt;/span&gt;
&lt;span class="err"&gt;```&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable with &lt;code&gt;--enable-experimental-code-block-annotations&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Inlining Control: &lt;code&gt;@inline(never)&lt;/code&gt; and &lt;code&gt;@inline(always)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Swift now exposes explicit inlining attributes for when the optimizer needs a nudge. &lt;code&gt;@inline(never)&lt;/code&gt; prevents a function from being inlined — useful for controlling code size or isolating a function during profiling. &lt;code&gt;@inline(always)&lt;/code&gt; forces inlining where the performance gain is known and worth the code size cost.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;never&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeInts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;randomized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;@inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;always&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeInts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;randomized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;@specialized&lt;/code&gt; for Generic Functions
&lt;/h3&gt;

&lt;p&gt;Generic functions generate a single implementation that works for all types. When a specific concrete type is used frequently, &lt;code&gt;@specialized&lt;/code&gt; tells the compiler to emit a dedicated, fully optimized version for that type — getting the performance of a non-generic function without giving up the generic API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@specialized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="kt"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UInt8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;histogram&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Values&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="nv"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="kt"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sequence&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;UInt8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Compiler emits a specialized version for [UInt8]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;@export(implementation)&lt;/code&gt; for ABI-Stable Libraries
&lt;/h3&gt;

&lt;p&gt;Library authors building ABI-stable frameworks can now use &lt;code&gt;@export(implementation)&lt;/code&gt; to expose a function's implementation to clients, allowing it to participate in more compiler optimizations across module boundaries — without breaking ABI.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;~Copyable&lt;/code&gt; and &lt;code&gt;~Escapable&lt;/code&gt; in Protocol Associated Types
&lt;/h3&gt;

&lt;p&gt;Protocols can now express that their associated types do not need to be copyable or escapable, enabling more expressive and efficient protocol designs — particularly for iterator and span-based APIs that need to avoid unnecessary copies.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;borrow&lt;/code&gt; and &lt;code&gt;mutate&lt;/code&gt; Accessors
&lt;/h3&gt;

&lt;p&gt;A new pair of accessors replaces the old &lt;code&gt;get&lt;/code&gt;/&lt;code&gt;set&lt;/code&gt; pattern for types that wrap unsafe pointers. &lt;code&gt;borrow&lt;/code&gt; provides a read-only reference without copying; &lt;code&gt;mutate&lt;/code&gt; provides a mutable reference. Together they allow non-copyable types to expose stored properties cleanly and safely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;borrow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;valuePointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pointee&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;valuePointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pointee&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;MutableRef&lt;/code&gt; for Hoisted Accesses
&lt;/h3&gt;

&lt;p&gt;Subscript accesses inside loops — like updating a dictionary value — can result in repeated redundant lookups. &lt;code&gt;MutableRef&lt;/code&gt; lets you hoist that access out of the loop manually, holding a stable mutable reference to the element for the duration of the operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;countRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MutableRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;countRef&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cross-Platform
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Official Swift SDK for Android
&lt;/h3&gt;

&lt;p&gt;Swift 6.3 ships the first official Swift SDK for Android. You can now build native Android programs in Swift, add Android as a target in your Swift packages, and integrate Swift code into existing Kotlin/Java Android apps using Swift Java and Swift Java JNI Core. This is a meaningful milestone — the Android target has existed as a grassroots community effort for years and is now a first-class, officially supported platform.&lt;/p&gt;

&lt;p&gt;To get started: &lt;a href="https://www.swift.org/documentation/articles/swift-sdk-for-android-getting-started.html" rel="noopener noreferrer"&gt;Getting Started with the Swift SDK for Android&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embedded Swift
&lt;/h3&gt;

&lt;p&gt;Embedded Swift continues to mature in Swift 6.3, with enhanced C interoperability, better debugging support, and meaningful progress toward a complete linkage model. If you are targeting microcontrollers or bare-metal environments, the &lt;a href="https://www.swift.org/blog/embedded-swift-improvements-coming-in-swift-6.3/" rel="noopener noreferrer"&gt;Embedded Swift improvements post&lt;/a&gt; covers the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Swift Build Preview in Swift Package Manager
&lt;/h3&gt;

&lt;p&gt;Swift 6.3 integrates a preview of Swift Build — a unified build engine across all supported platforms — into Swift Package Manager. The goal is a more consistent cross-platform build experience. Try it in your packages and report issues; it is opt-in for now.&lt;/p&gt;

&lt;p&gt;SPM also gains &lt;code&gt;swift package show-traits&lt;/code&gt; to discover the traits a package supports, and better support for prebuilt Swift Syntax binaries in shared macro libraries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Swift 6.3 and 6.4 together tell a clear story: the language is maturing and the team knows it. The ergonomics work — &lt;code&gt;anyAppleOS&lt;/code&gt;, improved memberwise initializers, better concurrency diagnostics — removes friction that has been accumulating for years. The cross-platform push, with an official Android SDK and continued Embedded Swift investment, reflects a genuine commitment to Swift outside the Apple ecosystem.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>WWDC 2026 - Apple Just Opened the Foundation Models Framework to Any LLM Provider</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 11 Jun 2026 11:07:49 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc-2026-apple-just-opened-the-foundation-models-framework-to-any-llm-provider-5ejn</link>
      <guid>https://dev.to/arshtechpro/wwdc-2026-apple-just-opened-the-foundation-models-framework-to-any-llm-provider-5ejn</guid>
      <description>&lt;p&gt;Until WWDC 2026, the Foundation Models framework had one rule: Apple's on-device model or nothing. That rule is gone.&lt;/p&gt;

&lt;p&gt;Session 339 introduces a public protocol layer that any LLM — a cloud API, an open-source local model, a fine-tune you host yourself — can implement. Once a provider ships a conforming Swift package, your existing &lt;code&gt;LanguageModelSession&lt;/code&gt; code works with it unchanged. No rewrites. No new session abstractions. One line swap.&lt;/p&gt;

&lt;p&gt;This article is not a transcript summary. It explains the decisions you now have to make as a developer building on Foundation Models in iOS 27 / macOS 27.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Situation Before This
&lt;/h2&gt;

&lt;p&gt;The Foundation Models framework launched in iOS 26 and was genuinely useful: free, private, offline, no API key, structured output via &lt;code&gt;@Generable&lt;/code&gt;. But it had a hard ceiling. The on-device model is about 3B parameters, not designed for general world knowledge, and has no long-context mode worth speaking of. If your feature needed anything beyond what that model handled, you were stitching together a completely separate SDK — URLSession calls, your own message history management, your own error handling, duplicated everything.&lt;/p&gt;

&lt;p&gt;The new protocol layer closes that gap. You write your session logic once against the Foundation Models API, and the model behind it becomes a deployment decision rather than an architectural one.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Actually Available Now
&lt;/h2&gt;

&lt;p&gt;Four model sources, one session API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The existing on-device model — free, private, offline&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SystemLanguageModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Apple's cloud model — 32K context, reasoning, Private Cloud Compute privacy guarantees&lt;/span&gt;
&lt;span class="c1"&gt;// let model = PrivateCloudComputeLanguageModel()&lt;/span&gt;

&lt;span class="c1"&gt;// A model you package and distribute via Swift Package Manager&lt;/span&gt;
&lt;span class="c1"&gt;// let model = try await CoreAILanguageModel(resourcesAt: modelURL)&lt;/span&gt;

&lt;span class="c1"&gt;// Any MLX-format model from HuggingFace&lt;/span&gt;
&lt;span class="c1"&gt;// let model = MLXLanguageModel(modelID: "mlx-community/my-model")&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Summarize this contract."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And first-party partners are already here. Gemini models are available through the Firebase Apple SDK, plugging directly into the Foundation Models framework using the same API — so the on-device Apple model and cloud-hosted Gemini sit behind the same interface. Anthropic is also listed as a launch partner.&lt;/p&gt;

&lt;p&gt;The practical upshot: you can build your feature against &lt;code&gt;SystemLanguageModel&lt;/code&gt; for dev and testing, then swap to Claude or Gemini for production without touching your session code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision You Now Have to Make
&lt;/h2&gt;

&lt;p&gt;Before writing any protocol conformance, figure out which tier your use case actually belongs to.&lt;/p&gt;

&lt;p&gt;The on-device model is good at focused tasks: summarization, extraction, classification, short-form generation, anything where you control the prompt tightly and the output is bounded. A 20B sparse model on a phone is enough to handle a meaningful slice of in-app AI tasks — structured extraction, classification, embedded summarization, tool routing. Apps that previously paid for cloud calls to do this can stop.&lt;/p&gt;

&lt;p&gt;The cloud tier is for everything else: long context, open-ended reasoning, conversations that run for many turns, tasks that need current world knowledge. Frontier reasoning, agentic loops, vision-language across many images — all still cheaper, more capable, or both via a cloud LLM. The build decision becomes "what can't run on-device" rather than "how big a model do I need."&lt;/p&gt;

&lt;p&gt;That framing matters because implementing a custom &lt;code&gt;LanguageModelExecutor&lt;/code&gt; is real work. Do not do it if the existing models cover your use case.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You Are Building a Provider Integration
&lt;/h2&gt;

&lt;p&gt;This is the engineering meat of session 339. Two protocols to implement, one Swift package to ship.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Two Protocols
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;LanguageModel&lt;/code&gt; describes what your model can do. &lt;code&gt;LanguageModelExecutor&lt;/code&gt; is where generation actually happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// LanguageModel: declare capabilities and hand the session a configuration&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MyLanguageModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LanguageModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="kt"&gt;Executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MyLanguageModelExecutor&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelCapabilities&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;LanguageModelCapabilities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toolCalling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guidedGeneration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;executorConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* API endpoint, auth, model variant, etc. */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// LanguageModelExecutor: translate the framework's request into your model's wire format&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MyLanguageModelExecutor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelExecutor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MyLanguageModel&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelExecutorGenerationRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyLanguageModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;streamingInto&lt;/span&gt; &lt;span class="nv"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelExecutorGenerationChannel&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;LanguageModel&lt;/code&gt; / &lt;code&gt;LanguageModelExecutor&lt;/code&gt; split is deliberate. A single model type can have multiple executor configurations — for example, a fast tier and a quality tier backed by the same model family. The session caches executor instances per configuration, so if a developer creates two sessions with identical configurations, they share an executor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prewarm
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;prewarm&lt;/code&gt; is called before the first request arrives. For a local model that loads weights from disk, use it to get weights into memory so the user does not wait on the first generation. For a remote API, you might warm a connection pool here or do nothing at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;prewarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Transcript&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;loadedModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;loadWeights&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;streamingInto&lt;/span&gt; &lt;span class="nv"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;loadedModel&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="nf"&gt;loadWeights&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// generate&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reading the Transcript
&lt;/h3&gt;

&lt;p&gt;The framework passes conversation history as a typed &lt;code&gt;Transcript&lt;/code&gt;, not a raw array of role/content strings. Your executor maps these to whatever your model expects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Transcript.Entry cases you will encounter:&lt;/span&gt;
&lt;span class="c1"&gt;// .instructions  → system prompt&lt;/span&gt;
&lt;span class="c1"&gt;// .prompt        → user message&lt;/span&gt;
&lt;span class="c1"&gt;// .toolCalls     → model-initiated tool invocations&lt;/span&gt;
&lt;span class="c1"&gt;// .toolOutput    → results from those tool calls&lt;/span&gt;
&lt;span class="c1"&gt;// .response      → assistant turn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This typed representation is cleaner than raw JSON message arrays and makes multi-turn context, tool call history, and system instructions all unambiguous. If your model's API uses OpenAI-compatible message formats, the mapping is mechanical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streaming Output Back
&lt;/h3&gt;

&lt;p&gt;The channel is how your executor sends generation back to the session. Three phases: metadata, token usage, then text deltas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;streamingInto&lt;/span&gt; &lt;span class="nv"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Tell the framework what model/request handled this&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateMetadata&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s"&gt;"modelID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my-model-2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"requestID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuidString&lt;/span&gt;
    &lt;span class="p"&gt;])))&lt;/span&gt;

    &lt;span class="c1"&gt;// Report input token count before generating&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;totalTokenCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;promptTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cachedTokenCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cachedTokens&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;totalTokenCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reasoningTokenCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="c1"&gt;// Stream tokens as they arrive&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;modelStream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handling Options You Do Not Support
&lt;/h3&gt;

&lt;p&gt;The session caller can request things your model might not support — greedy sampling, guided generation with a JSON schema, a specific reasoning level. The rule is: approximate where you can, throw where you cannot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Caller requested greedy sampling, your API only takes temperature — close enough&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generationOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sampling&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greedy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;apiRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Schema + tiny token budget is genuinely unsatisfiable — throw&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;budget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generationOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maximumResponseTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;budget&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;minimumTokensNeeded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;LanguageModelError&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsupportedCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;capability&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guidedGeneration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nv"&gt;debugDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Token budget too small for this schema."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The framework ships typed errors for every common failure: &lt;code&gt;contextSizeExceeded&lt;/code&gt;, &lt;code&gt;rateLimited&lt;/code&gt;, &lt;code&gt;refusal&lt;/code&gt;, &lt;code&gt;guardrailViolation&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt;, and more. Use them. Callers know how to handle them, and apps already built on Foundation Models will degrade gracefully when they see these errors from your model.&lt;/p&gt;

&lt;p&gt;Your own provider-specific errors — subscription limits, suspended accounts, model variants not yet provisioned — can be thrown as custom &lt;code&gt;Error&lt;/code&gt; types. Give them a proper &lt;code&gt;errorDescription&lt;/code&gt;; that string surfaces in developer-facing tooling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Custom Segments: When Text Is Not Enough
&lt;/h2&gt;

&lt;p&gt;Some models produce or consume things that are not text. The framework has a &lt;code&gt;Transcript.CustomSegment&lt;/code&gt; protocol for this.&lt;/p&gt;

&lt;p&gt;Define a type, use it in prompts, emit it from your executor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;AudioSegment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Transcript&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;CustomSegment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In a session&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;recording&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AudioSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuidString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audioFileURL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;respond&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Transcribe the key decisions from this meeting."&lt;/span&gt;
    &lt;span class="n"&gt;recording&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In the executor, emit back&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateCustomSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;AudioSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outputFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outputFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same mechanism works for web search citations, image outputs, retrieval chunks — anything that should live in the transcript with type information preserved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server-Side Tools
&lt;/h2&gt;

&lt;p&gt;If your model runs tools on the server side (web search is the common case), you do not expose them as client-side &lt;code&gt;Tool&lt;/code&gt; conformances. Instead, declare them on your model type and surface their output through the channel as custom segments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MyLanguageModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LanguageModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ServerTool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sendable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;webSearch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ServerTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;serverTools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ServerTool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Executor routes server events to the channel&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;apiResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;webSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateCustomSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="kt"&gt;WebSearchSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textDelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;tokenCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokenCount&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer using your model sees a coherent transcript that includes both the response text and the search results, typed and inspectable, without the server-side mechanics leaking through.&lt;/p&gt;




&lt;h2&gt;
  
  
  Packaging Your Provider
&lt;/h2&gt;

&lt;p&gt;The session is specific about how to ship this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Package.swift structure Apple recommends&lt;/span&gt;
&lt;span class="nv"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MyModelRuntime"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;          &lt;span class="c1"&gt;// inference engine, weights loader&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MyModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"MyModelRuntime"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;  &lt;span class="c1"&gt;// public LanguageModel conformance&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;testTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MyModelTests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"MyModel"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth noting from the session's packaging guidance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform targets.&lt;/strong&gt; Foundation Models supports iOS, macOS, visionOS, and watchOS. The Foundation Models framework is being released as open source, so your package could also be useful to developers who deploy Swift on Linux servers — consider supporting Linux too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependencies.&lt;/strong&gt; Every dependency translates to bytes that a developer ships to their users. Be deliberate about what is linked by your package. A bloated transitive dependency graph is a fast way to get your package rejected from app codebases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credentials.&lt;/strong&gt; Design initializers that guide developers toward secure usage rather than plain API key strings — persist tokens via Keychain rather than accepting them as plain strings.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Foundation Models has always been Apple's model or nothing. That changes in iOS 27. What Apple has built here is less a feature and more a distribution channel. Any LLM provider that ships a conforming Swift package can be dropped into apps that already use Foundation Models — apps that collectively handle session management, tool call loops, and error handling in a consistent way.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>ios</category>
      <category>llm</category>
      <category>mobile</category>
    </item>
    <item>
      <title>WWDC 2026 - What's New in SwiftUI - A Developer's Breakdown</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 11 Jun 2026 09:53:35 +0000</pubDate>
      <link>https://dev.to/arshtechpro/wwdc26-whats-new-in-swiftui-a-developers-breakdown-1333</link>
      <guid>https://dev.to/arshtechpro/wwdc26-whats-new-in-swiftui-a-developers-breakdown-1333</guid>
      <description>&lt;p&gt;WWDC26 brought a substantial round of updates to SwiftUI — not a ground-up redesign, but a lot of small limitations removed, new APIs that were clearly driven by real-world pain points, and meaningful performance improvements. This post walks through every major announcement so you know exactly what's available and when to reach for it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Look and Feel: Liquid Glass and the 2027 Releases
&lt;/h2&gt;

&lt;p&gt;The most immediately visible change costs you zero code. Apps built with SwiftUI automatically pick up the updated Liquid Glass appearance on the 2027 OS releases. The glass tint responds to the new system-level Liquid Glass slider without any changes on your part.&lt;/p&gt;

&lt;p&gt;On iPad, windows now dim when inactive, reinforcing which window has focus — again, automatic. On Mac, custom interactive Liquid Glass elements respond more fluidly to the mouse pointer.&lt;/p&gt;

&lt;p&gt;There are a few opt-in refinements available when you want tighter control:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responding to active state&lt;/strong&gt; — use the &lt;code&gt;appearsActive&lt;/code&gt; environment value to reduce opacity on custom elements when the window is inactive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SidebarFooterView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@Environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appearsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;appearsActive&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;MyAccountView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appearsActive&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Menu bar icons&lt;/strong&gt; — the menu bar now shows a minimal set of icons by default. Add &lt;code&gt;.labelStyle(.titleAndIcon)&lt;/code&gt; to a specific menu item to make its icon visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;CommandMenu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Stickers"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;openStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Store"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;systemImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"bag.fill"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;labelStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleAndIcon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Resizability on iPhone
&lt;/h2&gt;

&lt;p&gt;iPhone apps become resizable on iOS 27, which matters for iPhone Mirroring and running iPhone apps on iPad. Xcode 27's Live Previews now include resize handles so you can test this interactively without running on a device.&lt;/p&gt;

&lt;p&gt;If your app mixes UIKit and SwiftUI, check the session "Modernize your UIKit app" for specifics around screen geometry, size classes, and orientation handling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Toolbar APIs
&lt;/h2&gt;

&lt;p&gt;The toolbar has been a source of friction on smaller screens for a while. Three new APIs address this directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visibility priority&lt;/strong&gt; — mark a toolbar group as high-priority so it stays visible when space is tight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;ToolbarItemGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;UndoButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kt"&gt;RedoButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visibilityPriority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Overflow menu&lt;/strong&gt; — explicitly put secondary actions into the overflow menu rather than letting the system decide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;ToolbarOverflowMenu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;ChoosePhotoButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kt"&gt;ExportAsImageButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kt"&gt;ClearAllStickersButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pinned trailing item&lt;/strong&gt; — guarantee a button always appears in the trailing position, never hidden:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;ToolbarItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;placement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topBarPinnedTrailing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;ShareButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Minimize on scroll&lt;/strong&gt; — hide the navigation bar when the user scrolls down, maximizing content space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;ScrollView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;StickerListView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toolbarMinimizeBehavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onScrollDown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navigationBar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Prominent Tab Role
&lt;/h2&gt;

&lt;p&gt;Tabs can now be visually distinguished from the main tab row using the new &lt;code&gt;.prominent&lt;/code&gt; role. This is useful for actions like a shopping cart or a creation button that should stand apart from content navigation tabs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;TabView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Tab&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;EventsTab&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;Tab&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;HolidaysTab&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;Tab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prominent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;CartTab&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Document API Overhaul
&lt;/h2&gt;

&lt;p&gt;This is the most substantial new API surface in this release. The existing &lt;code&gt;FileDocument&lt;/code&gt; and &lt;code&gt;ReferenceFileDocument&lt;/code&gt; protocols are still there, but the 2027 releases introduce a new, more capable layer on top.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document creation context
&lt;/h3&gt;

&lt;p&gt;You can now define named creation sources and branch your initialization logic based on which one was selected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;DocumentCreationSource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;blank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"blank"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"photo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Stickers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Scene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;DocumentGroupLaunchScene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Create a Sticker Page"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;NewDocumentButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"New Sticker Page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;NewDocumentButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sticker Page from Photo…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;DocumentGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;StickerPageDocumentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;StickerPageDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WritableDocument and DocumentWriter
&lt;/h3&gt;

&lt;p&gt;The new &lt;code&gt;WritableDocument&lt;/code&gt; protocol separates the document model from the disk-writing logic. You provide a &lt;code&gt;snapshot()&lt;/code&gt; method that captures the current state, and a &lt;code&gt;Writer&lt;/code&gt; that knows how to serialize it.&lt;/p&gt;

&lt;p&gt;The writer's &lt;code&gt;write&lt;/code&gt; method is &lt;code&gt;nonisolated&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt;, so heavy I/O stays off the main actor. You can compare current and previous snapshots to write only what changed, and report progress using Foundation's &lt;code&gt;Subprogress&lt;/code&gt; API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DocumentWriter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="kt"&gt;Snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PageSnapshot&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UTType&lt;/span&gt;

    &lt;span class="kd"&gt;nonisolated&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sending&lt;/span&gt; &lt;span class="kt"&gt;PageSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sending&lt;/span&gt; &lt;span class="kt"&gt;PageSnapshot&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="nv"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;consuming&lt;/span&gt; &lt;span class="kt"&gt;Subprogress&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;contentType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;conforms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stickerDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// write custom format&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;contentType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;conforms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supporting multiple export formats is a matter of adding types to &lt;code&gt;writableContentTypes&lt;/code&gt; and adding branches in &lt;code&gt;write&lt;/code&gt;. The &lt;code&gt;ReadableDocument&lt;/code&gt; and &lt;code&gt;DocumentReader&lt;/code&gt; protocols mirror this structure for reading.&lt;/p&gt;

&lt;p&gt;This API works with the &lt;code&gt;@Observable&lt;/code&gt; macro, so views update only when the specific properties they depend on actually change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reorderable Containers
&lt;/h2&gt;

&lt;p&gt;Drag-to-reorder is now available on any container, not just &lt;code&gt;List&lt;/code&gt;. Apply &lt;code&gt;.reorderable()&lt;/code&gt; to your &lt;code&gt;ForEach&lt;/code&gt; and &lt;code&gt;.reorderContainer&lt;/code&gt; to the parent, and SwiftUI handles the drag interaction and animation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stickers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;sticker&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="kt"&gt;StickerListItemView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reorderable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reorderContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Sticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;difference&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;difference&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;stickers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same code works on &lt;code&gt;LazyVGrid&lt;/code&gt; — you don't need to rewrite anything when switching container types. Reordering also comes to watchOS for the first time this release.&lt;/p&gt;

&lt;p&gt;For applying the &lt;code&gt;ReorderDifference&lt;/code&gt; back to your array, the recommended approach uses the &lt;code&gt;swift-collections&lt;/code&gt; package from swift.org:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;OrderedCollections&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;ReorderDifference&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="kt"&gt;CollectionID&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;ReorderableSingleCollectionIdentifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Identifiable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;ItemID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;OrderedDictionary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;uniqueKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// resolve destination and move keys&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Swipe Actions on Any View
&lt;/h2&gt;

&lt;p&gt;Previously, &lt;code&gt;.swipeActions&lt;/code&gt; only worked inside &lt;code&gt;List&lt;/code&gt;. Now it works on any view inside a scroll container. Add &lt;code&gt;.swipeActionsContainer()&lt;/code&gt; to the scroll view to coordinate the interactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;ScrollView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;LazyVStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stickers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;sticker&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;StickerListItemView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swipeActions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;DeleteButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;swipeActionsContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Confirmation Dialogs and Alerts with Item Binding
&lt;/h2&gt;

&lt;p&gt;Both &lt;code&gt;.confirmationDialog&lt;/code&gt; and &lt;code&gt;.alert&lt;/code&gt; now accept the same item-binding pattern that sheets use. Pass a binding to an optional item; when the item is set, the dialog appears with that item in scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirmationDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Delete?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$stickerToDelete&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;sticker&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="kt"&gt;DeleteStickerButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sticker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This replaces the pattern of managing a separate &lt;code&gt;isPresented&lt;/code&gt; Bool alongside a selected-item variable.&lt;/p&gt;




&lt;h2&gt;
  
  
  AsyncImage Caching
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AsyncImage&lt;/code&gt; now respects standard HTTP cache headers by default, so images loaded from the network are cached without any code changes. When scrolling back to previously loaded content, images appear immediately from cache.&lt;/p&gt;

&lt;p&gt;When you need more control, you can provide a custom &lt;code&gt;URLRequest&lt;/code&gt; per image and attach a custom &lt;code&gt;URLSession&lt;/code&gt; with a configured &lt;code&gt;URLCache&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@Observable&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;StickerStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;imageSession&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URLSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URLSessionConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URLCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;memoryCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;diskCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;URLSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="kt"&gt;AsyncImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URLRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imageURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;cachePolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returnCacheDataElseLoad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asyncImageURLSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;StickerStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imageSession&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  @State Is Now a Macro — With Lazy Initialization
&lt;/h2&gt;

&lt;p&gt;This is a subtle but impactful change. &lt;code&gt;@State&lt;/code&gt; has been converted from a Dynamic Property to a macro. The practical effect: &lt;code&gt;@Observable&lt;/code&gt; classes stored in &lt;code&gt;@State&lt;/code&gt; are now initialized lazily — only once for the lifetime of the view, not on every reinitialization of the parent.&lt;/p&gt;

&lt;p&gt;Previously, if a parent view reinitializes &lt;code&gt;StickerStoreView&lt;/code&gt;, a new &lt;code&gt;StickerStore()&lt;/code&gt; would be created each time (and immediately discarded). Now, the class is only ever created once. This behavior is back-ported to iOS 17, macOS 14, and aligned releases.&lt;/p&gt;

&lt;p&gt;One source-breaking edge case to watch for: if you assign a default value in the property declaration &lt;em&gt;and&lt;/em&gt; assign a different value in &lt;code&gt;init&lt;/code&gt;, Xcode 27 will show a "variable used before being initialized" error. The fix is to remove the default value from the declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before — causes error&lt;/span&gt;
&lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;StickerPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;StickerPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// error&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After — correct&lt;/span&gt;
&lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;StickerPage&lt;/span&gt;

&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;StickerPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ContentBuilder: Better Compiler Performance
&lt;/h2&gt;

&lt;p&gt;If your app has complex, deeply nested SwiftUI views, you may have seen "The compiler is unable to type-check this expression in reasonable time." This happens because &lt;code&gt;Section&lt;/code&gt;, &lt;code&gt;Group&lt;/code&gt;, &lt;code&gt;ForEach&lt;/code&gt;, and similar containers each have multiple overloads, and the compiler has to explore every combination.&lt;/p&gt;

&lt;p&gt;The 2027 releases introduce &lt;code&gt;ContentBuilder&lt;/code&gt;, a unified builder type that replaces the per-container overloads. This reduces type-checking to a single path through the decision tree, which translates to meaningfully faster compile times. &lt;code&gt;ContentBuilder&lt;/code&gt; is available for any deployment target because it's built on top of the existing &lt;code&gt;ViewBuilder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can use it directly when needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@ContentBuilder&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;stickerLibraryView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The improvement applies when building with Xcode 27 regardless of your minimum deployment target.&lt;/p&gt;




&lt;h2&gt;
  
  
  SwiftUI Agent Skills in Xcode 27
&lt;/h2&gt;

&lt;p&gt;Xcode 27 ships two new agent skills for the Coding Assistant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SwiftUI Specialist&lt;/strong&gt; — enforces SwiftUI best practices as you write code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What's New in SwiftUI&lt;/strong&gt; — guides adoption of the new 2027 APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are available inside Xcode 27's Coding Assistant. If you use other tools, you can export them as markdown files with &lt;code&gt;xcrun agent skills export&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;p&gt;If you want to work through these APIs systematically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build your existing app in Xcode 27 and check the updated Liquid Glass appearance — it requires no code changes.&lt;/li&gt;
&lt;li&gt;If you have a document-based app, the new &lt;code&gt;WritableDocument&lt;/code&gt; / &lt;code&gt;ReadableDocument&lt;/code&gt; protocols are worth evaluating for the performance and multi-format benefits.&lt;/li&gt;
&lt;li&gt;Audit your toolbar setup, especially on compact screens, using the three new toolbar APIs.&lt;/li&gt;
&lt;li&gt;If you have complex views with compiler performance issues, upgrading to Xcode 27 alone should help due to &lt;code&gt;ContentBuilder&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Switch any &lt;code&gt;@State&lt;/code&gt;-managed &lt;code&gt;@Observable&lt;/code&gt; classes over and verify the lazy initialization behavior works as expected in your initialization paths.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
