<?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>Goodbye pbxproj: A Friendly Guide to Xcode 27.2's New JSON Project Format</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 24 Sep 2026 16:08:54 +0000</pubDate>
      <link>https://dev.to/arshtechpro/goodbye-pbxproj-a-friendly-guide-to-xcode-272s-new-json-project-format-bhh</link>
      <guid>https://dev.to/arshtechpro/goodbye-pbxproj-a-friendly-guide-to-xcode-272s-new-json-project-format-bhh</guid>
      <description>&lt;p&gt;If you've built iOS apps on a team, you know this moment. You pull &lt;code&gt;main&lt;/code&gt;, Git says &lt;code&gt;CONFLICT (content): Merge conflict in project.pbxproj&lt;/code&gt;, and you open a wall of 24-character hex IDs.&lt;/p&gt;

&lt;p&gt;Xcode 27.2 finally changes that. Here's what's new, explained without jargon.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Xcode 27.2 replaces the old &lt;code&gt;project.pbxproj&lt;/code&gt; property list with a new JSON-based &lt;code&gt;project.xcproj&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;New projects use the new format by default. Existing projects are not converted automatically, and both formats work side by side.&lt;/li&gt;
&lt;li&gt;Xcode 27.0 and 27.2 can both open a JSON project. Xcode 26 cannot.&lt;/li&gt;
&lt;li&gt;Diffs get smaller, merge conflicts become rare, and you can read the file without special knowledge.&lt;/li&gt;
&lt;li&gt;Check your tools (CocoaPods, fastlane, scripts) before you switch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First, what is an &lt;code&gt;.xcodeproj&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;MyApp.xcodeproj&lt;/code&gt; looks like a file, but it is a folder. Right-click it and choose &lt;strong&gt;Show Package Contents&lt;/strong&gt; to see what's inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MyApp.xcodeproj/
├── project.pbxproj      &amp;lt;- the old project description
├── project.xcworkspace/
├── xcshareddata/        &amp;lt;- shared schemes, Package.resolved
└── xcuserdata/          &amp;lt;- your personal UI state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only one file changes in 27.2. &lt;code&gt;project.xcproj&lt;/code&gt; replaces &lt;code&gt;project.pbxproj&lt;/code&gt;. Nothing else in the bundle changes, so schemes, &lt;code&gt;Package.resolved&lt;/code&gt;, and &lt;code&gt;xcuserdata&lt;/code&gt; stay the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the old format hurt
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;project.pbxproj&lt;/code&gt; uses an old NeXTSTEP-era plist syntax. It stores your project as one large flat list of objects, and every object points to the others by random hex IDs.&lt;/p&gt;

&lt;p&gt;To add a single Swift file, Xcode has to write it in &lt;strong&gt;four&lt;/strong&gt; places:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;PBXFileReference&lt;/code&gt; so the file exists&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;PBXBuildFile&lt;/code&gt; so it gets compiled&lt;/li&gt;
&lt;li&gt;An entry in a &lt;code&gt;PBXGroup&lt;/code&gt; so it shows in the navigator&lt;/li&gt;
&lt;li&gt;An entry in the &lt;code&gt;PBXSourcesBuildPhase&lt;/code&gt; so it reaches the target&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Xcode generates both IDs fresh, so a teammate who adds a different file on their branch writes different IDs into the same four places. That's where the classic merge conflict comes from.&lt;/p&gt;

&lt;p&gt;Build settings had the same problem. Each configuration (Debug, Release) kept its own full copy of the settings, so changing the deployment target meant editing two places.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the new file looks like
&lt;/h2&gt;

&lt;p&gt;Here's a small example app in the new format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&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;"default-configuration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Debug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&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="s2"&gt;"Debug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Release"&lt;/span&gt;&lt;span class="p"&gt;,],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sources"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"children"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WeatherApp.swift"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"target-membership"&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="s2"&gt;"Weather/compile-sources"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ForecastView.swift"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target-membership"&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="s2"&gt;"Weather/compile-sources"&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="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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"product-type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"build-phases"&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="s2"&gt;"compile-sources"&lt;/span&gt;&lt;span class="p"&gt;,],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"build-settings"&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;"PRODUCT_BUNDLE_IDENTIFIER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"com.example.weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"SWIFT_VERSION"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6.0"&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="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;"build-settings"&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;"IPHONEOS_DEPLOYMENT_TARGET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"27.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SWIFT_OPTIMIZATION_LEVEL[config=Debug]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-Onone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SWIFT_OPTIMIZATION_LEVEL[config=Release]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-O"&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="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;You can probably read it without any explanation. Let's go through the three main ideas.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. It's a tree, not a flat list
&lt;/h3&gt;

&lt;p&gt;The file follows the structure you see in Xcode's UI. Instead of one big &lt;code&gt;objects&lt;/code&gt; table, it is split into sections like &lt;code&gt;files&lt;/code&gt;, &lt;code&gt;targets&lt;/code&gt;, and &lt;code&gt;build-settings&lt;/code&gt;, so a diff looks like what you actually did in the interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Files say which target they belong to
&lt;/h3&gt;

&lt;p&gt;This is the most important change. In the old format, the target kept a list of its files. In the new format, each file lists its targets:&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ForecastView.swift"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target-membership"&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="s2"&gt;"Weather/compile-sources"&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;Read &lt;code&gt;Weather/compile-sources&lt;/code&gt; as "compile this file in the Weather target." It combines the target name with the build phase, and no UUID is involved. Adding a file is now &lt;strong&gt;one line&lt;/strong&gt; in &lt;strong&gt;one place&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you need more detail, the entry becomes an object. For example, marking a header as public is done right there on the file, instead of inside &lt;code&gt;PBXBuildFile.settings.ATTRIBUTES&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Build settings are written once
&lt;/h3&gt;

&lt;p&gt;A setting that's the same in every configuration now appears once. When Debug and Release differ, the key carries a condition:&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="nl"&gt;"SWIFT_OPTIMIZATION_LEVEL[config=Debug]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-Onone"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"SWIFT_OPTIMIZATION_LEVEL[config=Release]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-O"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've used &lt;code&gt;.xcconfig&lt;/code&gt; files, this &lt;code&gt;[config=...]&lt;/code&gt; syntax will look familiar. In one real migration, 161 lines of &lt;code&gt;XCBuildConfiguration&lt;/code&gt; shrank to a single &lt;code&gt;build-settings&lt;/code&gt; block, and the whole file went from 300 lines of property list to 123 lines of JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: IDs are mostly gone
&lt;/h3&gt;

&lt;p&gt;IDs are only assigned where they're needed, meaning targets and build products. Everything else is referenced by name or path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotcha: it's "JSON", but with trailing commas
&lt;/h2&gt;

&lt;p&gt;You might have noticed the trailing commas in the examples above. That's intentional. The format allows trailing commas, so a plain &lt;code&gt;JSON.parse&lt;/code&gt; can't read it as-is. Apple's open-source library uses JSON5 encoding for this. If you're writing a script, use a JSON5-tolerant parser or Apple's library (see below) instead of &lt;code&gt;jq&lt;/code&gt; or &lt;code&gt;JSON.parse&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to switch an existing project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  In Xcode
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;project&lt;/strong&gt; at the top of the Project navigator.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;File inspector&lt;/strong&gt; (&lt;code&gt;Option-Command-1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Project Document&lt;/strong&gt;, set &lt;strong&gt;Project Format&lt;/strong&gt; to &lt;strong&gt;JSON&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Confirm the dialog.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;project.pbxproj&lt;/code&gt; is deleted and &lt;code&gt;project.xcproj&lt;/code&gt; takes its place. Commit the change as its own commit, with no other edits, so it's easy to review and revert.&lt;/p&gt;

&lt;h3&gt;
  
  
  From the command line
&lt;/h3&gt;

&lt;p&gt;This is handy for CI or for converting many projects at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcodebuild &lt;span class="nt"&gt;-project&lt;/span&gt; MyApp.xcodeproj &lt;span class="nt"&gt;-convert-project&lt;/span&gt; &lt;span class="s2"&gt;"Xcode Project"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command converts the project, and it does the same thing as choosing JSON in the File inspector.&lt;/p&gt;

&lt;h2&gt;
  
  
  New tooling: &lt;code&gt;xcprojformatter&lt;/code&gt; and an open-source library
&lt;/h2&gt;

&lt;p&gt;Apple published the format openly. &lt;code&gt;xcode-project-format&lt;/code&gt; is a Swift library for reading, writing, and manipulating the &lt;code&gt;project.xcproj&lt;/code&gt; format, so tools like generators, linters, and validators don't each have to reverse-engineer it.&lt;/p&gt;

&lt;p&gt;Reading a project takes a few 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;XcodeProjectFormat&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&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;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;contentsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;projectURL&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;project&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;XCSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;jsonRepresentation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&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;target&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;targets&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;target&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Xcode 27.2 also includes &lt;code&gt;xcprojformatter&lt;/code&gt; in &lt;code&gt;/usr/bin&lt;/code&gt;. It validates and reformats files that already use &lt;code&gt;xcproj&lt;/code&gt;. It is not a converter from &lt;code&gt;pbxproj&lt;/code&gt;. For CI, think of it as &lt;code&gt;swift-format&lt;/code&gt; for your project file. Run &lt;code&gt;xcprojformatter --help&lt;/code&gt; to see its options, and consider adding a check to CI so hand edits (from people or AI agents) stay in canonical form.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about Tuist, XcodeGen, CocoaPods, fastlane?
&lt;/h2&gt;

&lt;p&gt;This is the main reason to wait before switching.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anything that parses &lt;code&gt;project.pbxproj&lt;/code&gt; directly needs an update.&lt;/strong&gt; That includes CocoaPods through the &lt;code&gt;xcodeproj&lt;/code&gt; gem, fastlane actions that bump versions or change settings, project generators, and custom scripts. As of the 27.2 release, support is still rolling out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Swift &lt;code&gt;XcodeProj&lt;/code&gt; library already has experimental support.&lt;/strong&gt; Version 9.17.0 added it on September 17, 2026. Its maintainers say to expect details to change and to check a converted project before committing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some tools don't support it yet.&lt;/strong&gt; For example, Capacitor has an open issue because &lt;code&gt;cap sync ios&lt;/code&gt; only parses &lt;code&gt;.pbxproj&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generators keep working.&lt;/strong&gt; Tuist, XcodeGen, Bazel, SwiftPM, and xcconfig-based workflows continue to work unchanged and can adopt the new format at their own pace.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why now? (Hint: AI agents)
&lt;/h2&gt;

&lt;p&gt;Apple filed its announcement under &lt;strong&gt;Coding Intelligence&lt;/strong&gt;. Apple says directly that the new format makes it easier for coding agents to work with Xcode projects. When an agent (or a human) can change one setting by editing one readable line, instead of updating several ID cross-references, there are far fewer ways to break the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you switch?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo dev or small team, everyone on Xcode 27&lt;/td&gt;
&lt;td&gt;Switch now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hand-maintained &lt;code&gt;.xcodeproj&lt;/code&gt; with frequent conflicts&lt;/td&gt;
&lt;td&gt;Switch, since you gain the most&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Someone on the team still uses Xcode 26&lt;/td&gt;
&lt;td&gt;Wait&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CocoaPods, fastlane project edits, or custom pbxproj scripts&lt;/td&gt;
&lt;td&gt;Check each tool first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You generate projects with Tuist or XcodeGen&lt;/td&gt;
&lt;td&gt;Nothing urgent, since your manifest is the source of truth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;code&gt;project.xcproj&lt;/code&gt; isn't a new build system or a Swift manifest. It's the same project model written in a form people can actually read. Adding a file is one line, a setting is one line, and a merge conflict becomes something you can resolve by reading it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apple: &lt;a href="https://developer.apple.com/documentation/xcode/updating-your-xcode-project-configuration-file-format" rel="noopener noreferrer"&gt;Updating your Xcode project configuration file format&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>ai</category>
      <category>xcode</category>
    </item>
    <item>
      <title>Orca: The Agent Development Environment for Running AI Coding Agents in Parallel</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sun, 20 Sep 2026 06:00:36 +0000</pubDate>
      <link>https://dev.to/arshtechpro/orca-explained-the-agent-development-environment-for-running-ai-coding-agents-in-parallel-440n</link>
      <guid>https://dev.to/arshtechpro/orca-explained-the-agent-development-environment-for-running-ai-coding-agents-in-parallel-440n</guid>
      <description>&lt;p&gt;If you use Claude Code, Codex, or another AI coding agent in your terminal, you have probably hit this wall: the agent is busy on one task, you want to start a second one, and now you are juggling branches, stashing changes, and opening five terminal windows that all look the same.&lt;/p&gt;

&lt;p&gt;Orca is a desktop app built to solve exactly that. This article explains what it is, how it differs from Cursor, what it costs, and where it falls short.&lt;/p&gt;

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

&lt;p&gt;Orca calls itself an &lt;strong&gt;ADE&lt;/strong&gt;, an Agent Development Environment. The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A traditional &lt;strong&gt;IDE&lt;/strong&gt; is built around one human typing code.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;ADE&lt;/strong&gt; is built around you &lt;em&gt;supervising several AI agents&lt;/em&gt; that write code at the same time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, Orca is a desktop app (macOS, Windows, Linux) where every task you start gets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Its own &lt;strong&gt;git worktree&lt;/strong&gt; (an isolated copy of your repo on its own branch)&lt;/li&gt;
&lt;li&gt;Its own &lt;strong&gt;agent terminal&lt;/strong&gt; (Claude Code, Codex, Gemini, Cursor CLI, and so on)&lt;/li&gt;
&lt;li&gt;Its own &lt;strong&gt;browser tab&lt;/strong&gt; for previewing the app&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A quick primer on git worktrees
&lt;/h2&gt;

&lt;p&gt;Worktrees are the core idea behind Orca, so it is worth a 30-second refresher.&lt;/p&gt;

&lt;p&gt;Normally, one repo folder has one checked-out branch. A worktree lets you check out &lt;em&gt;another&lt;/em&gt; branch into a &lt;em&gt;separate folder&lt;/em&gt; that shares the same git history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../fix-login-race &lt;span class="nt"&gt;-b&lt;/span&gt; fix-login-race
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have two folders, two branches, one repo. No stashing needed.&lt;/p&gt;

&lt;p&gt;Orca automates this. Click "+", name your task, pick an agent, and Orca creates a real git worktree and launches the agent inside it. Because these are standard worktrees, you can always &lt;code&gt;cd&lt;/code&gt; into one and use plain git.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a typical workflow look like?
&lt;/h2&gt;

&lt;p&gt;The Orca docs describe a "first 3-agent session" that sums up the whole product:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add a repo.&lt;/strong&gt; Point Orca at a local checkout. It uses your default branch (for example &lt;code&gt;origin/main&lt;/code&gt;) as the base for new worktrees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a worktree.&lt;/strong&gt; Give the task a name like &lt;code&gt;fix-login-race&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick an agent.&lt;/strong&gt; Choose Claude Code, Codex, Cursor CLI, or another supported agent. Orca launches its CLI in the right directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Race agents.&lt;/strong&gt; Repeat twice more with different agents and paste the same prompt into each:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fix-login-race&lt;/code&gt; with Claude Code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fix-login-race-2&lt;/code&gt; with Codex&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fix-login-race-3&lt;/code&gt; with Cursor CLI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split panes&lt;/strong&gt; so you can watch all three working at once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review and ship.&lt;/strong&gt; Open each diff, leave inline comments to send back to the best agent, then commit and push from inside Orca. Delete the losing worktrees in one click.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That loop (add, worktree, agent, split, diff, ship) is essentially the whole product. Everything else is a deeper version of one of those steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Parallel worktrees.&lt;/strong&gt; Every task is isolated, so five agents can work on the same repo without overwriting each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bring your own agent.&lt;/strong&gt; Orca ships preconfigured for a long list of CLI agents, including Claude Code, Codex, Gemini, Cursor CLI, GitHub Copilot, OpenCode, Amp, Goose, Cline, Kiro, and Qwen Code, and any other CLI agent can be added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Annotate AI diffs.&lt;/strong&gt; Leave markdown comments on specific diff lines, batch them, and send them back to the agent as feedback. You can also inspect CI, resolve conflicts, and open PRs in the app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design Mode.&lt;/strong&gt; Each worktree gets a real Chromium window. Click a UI element and Orca sends its HTML, CSS, and a cropped screenshot to your agent. Useful for "fix this button" style front-end work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal.&lt;/strong&gt; GPU-rendered, with unlimited splits, scrollback that survives restarts, and scrollback search. On first launch it can import your Ghostty settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editor.&lt;/strong&gt; It includes a VS Code-style (Monaco) editor with autosave, so you can make manual edits without leaving the app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSH worktrees.&lt;/strong&gt; Run agents on a powerful remote machine with full file editing, git, and terminals, plus auto-reconnect and port forwarding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub, Linear, and Jira integration.&lt;/strong&gt; Browse PRs and issues, open a worktree straight from a task, and review PRs without switching apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orca CLI.&lt;/strong&gt; Agents can drive Orca too, for example creating worktrees themselves, which enables orchestration and scheduled automations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage tracking.&lt;/strong&gt; See Claude and Codex usage and rate-limit reset times, and swap between Codex accounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile companion.&lt;/strong&gt; iOS and Android apps let you check agent status, get notifications, and keep terminal work moving when you are away from your desk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Orca like Cursor?
&lt;/h2&gt;

&lt;p&gt;Short answer: &lt;strong&gt;they overlap, but they solve different problems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cursor&lt;/strong&gt; is an AI-first code editor (a fork of VS Code). The AI lives &lt;em&gt;inside&lt;/em&gt; the editor: autocomplete as you type, chat in a sidebar, and an agent mode. You are the main author, and the AI assists you in one workspace. You pay Cursor for access to the models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orca&lt;/strong&gt; is an orchestration layer for &lt;em&gt;CLI agents&lt;/em&gt;. It does not provide its own model. Instead, it runs the agents you already have (including Cursor's own CLI agent) side by side, each in its own isolated branch, and gives you tools to review and merge their output.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Orca&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core idea&lt;/td&gt;
&lt;td&gt;Manage many agents in parallel&lt;/td&gt;
&lt;td&gt;AI-assisted editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built on&lt;/td&gt;
&lt;td&gt;Desktop app wrapping CLI agents, terminals, browser, editor&lt;/td&gt;
&lt;td&gt;Fork of VS Code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI models&lt;/td&gt;
&lt;td&gt;Bring your own (Claude Code, Codex, Gemini, etc.)&lt;/td&gt;
&lt;td&gt;Cursor's subscription and models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel agents&lt;/td&gt;
&lt;td&gt;First-class, one worktree per task&lt;/td&gt;
&lt;td&gt;Supported, but not the main workflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inline autocomplete while you type&lt;/td&gt;
&lt;td&gt;Not a headline feature&lt;/td&gt;
&lt;td&gt;Yes, a core feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Yes, MIT&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platforms&lt;/td&gt;
&lt;td&gt;macOS, Windows, Linux&lt;/td&gt;
&lt;td&gt;macOS, Windows, Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price of the tool itself&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free tier plus paid plans&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A useful way to think about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you mostly &lt;strong&gt;write code yourself&lt;/strong&gt; and want AI help as you type, Cursor (or a similar AI editor) is the more natural fit.&lt;/li&gt;
&lt;li&gt;If you mostly &lt;strong&gt;delegate tasks to agents&lt;/strong&gt; and your job is increasingly to review, compare, and merge their output, Orca is designed for that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pricing: is Orca free?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes. The Orca app is free and open source under the MIT license.&lt;/strong&gt; There is no paid tier listed on the website.&lt;/p&gt;

&lt;p&gt;There are two things to be aware of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You pay for the agents.&lt;/strong&gt; Orca is not a model. You need your own Claude, Codex, Gemini, or other subscription or API key. Running three agents in parallel can use your quota roughly three times as fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise is "contact us."&lt;/strong&gt; There is an Enterprise page covering security reviews, self-hosting, rollout help, and SOC 2 readiness, but no public pricing. You have to email the team.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Installing Orca
&lt;/h2&gt;

&lt;p&gt;Download builds for each platform from the &lt;a href="https://www.onorca.dev/download" rel="noopener noreferrer"&gt;download page&lt;/a&gt; or GitHub Releases. On macOS you can also use Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; stablyai/orca/orca
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On first launch, Orca offers to import your &lt;code&gt;~/.claude&lt;/code&gt;, &lt;code&gt;~/.codex&lt;/code&gt;, and Ghostty settings.&lt;/li&gt;
&lt;li&gt;On Linux, pick the AppImage if you want automatic updates. The CLI is named &lt;code&gt;orca-ide&lt;/code&gt; so it does not clash with the GNOME Orca screen reader.&lt;/li&gt;
&lt;li&gt;The app auto-updates on a stable channel, with optional release-candidate builds for early features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who should try Orca?
&lt;/h2&gt;

&lt;p&gt;Orca is worth a look if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already use one or more CLI coding agents and feel limited by running one task at a time.&lt;/li&gt;
&lt;li&gt;You want to compare how different agents handle the same bug.&lt;/li&gt;
&lt;li&gt;You want a Claude Code or Codex workflow on Windows or Linux with a proper UI around it.&lt;/li&gt;
&lt;li&gt;You like running agents on a remote machine and checking on them from your phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can probably skip it if you rarely use agents, prefer AI autocomplete while you type, or want a single all-in-one subscription that handles the models for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/stablyai/orca" rel="noopener noreferrer"&gt;https://github.com/stablyai/orca&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>tooling</category>
      <category>agents</category>
    </item>
    <item>
      <title>Worktrunk: Git Worktrees Made Simple for Parallel AI Agents</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sat, 19 Sep 2026 21:08:11 +0000</pubDate>
      <link>https://dev.to/arshtechpro/worktrunk-git-worktrees-made-simple-for-parallel-ai-agents-1106</link>
      <guid>https://dev.to/arshtechpro/worktrunk-git-worktrees-made-simple-for-parallel-ai-agents-1106</guid>
      <description>&lt;p&gt;AI coding agents like Claude Code and Codex can now work on longer tasks without supervision. That means you can realistically run several of them at once, each on a different feature or bug.&lt;/p&gt;

&lt;p&gt;The catch: if they all work in the same folder, they overwrite each other's changes. Git has a built-in answer for this called &lt;strong&gt;worktrees&lt;/strong&gt;. A worktree is a separate working directory attached to the same repository, so each branch can live in its own folder at the same time.&lt;/p&gt;

&lt;p&gt;The problem is that git's worktree commands are clunky. Just starting a new one looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feat ../repo.feat
&lt;span class="nb"&gt;cd&lt;/span&gt; ../repo.feat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You type the branch name three times. Cleaning up afterward takes another three commands. Do this ten times a day and it gets old fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Worktrunk is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/max-sixty/worktrunk" rel="noopener noreferrer"&gt;Worktrunk&lt;/a&gt; is a command-line tool, written in Rust, that makes worktrees as easy to use as regular branches. You refer to everything by branch name, and Worktrunk works out the folder paths for you.&lt;/p&gt;

&lt;p&gt;It's open source (MIT or Apache-2.0), was released at the start of 2026, and already has over 5k stars on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core commands
&lt;/h2&gt;

&lt;p&gt;Here's how Worktrunk compares with plain git:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Worktrunk&lt;/th&gt;
&lt;th&gt;Plain git&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Switch to a worktree&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wt switch feat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd ../repo.feat&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create and start an agent&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wt switch -c -x claude feat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git worktree add -b feat ../repo.feat &amp;amp;&amp;amp; cd ../repo.feat &amp;amp;&amp;amp; claude&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clean up&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wt remove&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd ../repo &amp;amp;&amp;amp; git worktree remove ../repo.feat &amp;amp;&amp;amp; git branch -d feat&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List with status&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wt list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git worktree list&lt;/code&gt; (paths only)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Four commands cover most of what you'll do day to day.&lt;/p&gt;

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

&lt;p&gt;Install with Homebrew (macOS and Linux):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;worktrunk &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; wt config shell &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Cargo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;worktrunk &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; wt config shell &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;wt config shell install&lt;/code&gt; step matters. It adds shell integration so &lt;code&gt;wt&lt;/code&gt; can actually change your current directory.&lt;/p&gt;

&lt;p&gt;Create a worktree for a new feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wt switch &lt;span class="nt"&gt;--create&lt;/span&gt; feature-auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the branch and the worktree, then moves you into it. Check all your worktrees and their status with:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;When you're done, you can open a PR as usual and run &lt;code&gt;wt remove&lt;/code&gt; after it merges. Or merge locally with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wt merge main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That commits your changes, rebases onto main, merges, and removes the worktree and branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running agents in parallel
&lt;/h2&gt;

&lt;p&gt;This is where Worktrunk shines. Start three agents on three tasks, each in its own isolated worktree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wt switch &lt;span class="nt"&gt;-x&lt;/span&gt; claude &lt;span class="nt"&gt;-c&lt;/span&gt; feature-a &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s1"&gt;'Add user authentication'&lt;/span&gt;
wt switch &lt;span class="nt"&gt;-x&lt;/span&gt; claude &lt;span class="nt"&gt;-c&lt;/span&gt; feature-b &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s1"&gt;'Fix the pagination bug'&lt;/span&gt;
wt switch &lt;span class="nt"&gt;-x&lt;/span&gt; claude &lt;span class="nt"&gt;-c&lt;/span&gt; feature-c &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s1"&gt;'Write tests for the API'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-x&lt;/code&gt; flag runs a command after switching, and everything after &lt;code&gt;--&lt;/code&gt; is passed to that command. No agent touches another agent's files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras worth knowing
&lt;/h2&gt;

&lt;p&gt;Beyond the basics, Worktrunk includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt; that run commands when a worktree is created or merged, such as installing dependencies or starting a dev server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM-generated commit messages&lt;/strong&gt; based on your diff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build cache copying&lt;/strong&gt; so a new worktree can reuse &lt;code&gt;node_modules/&lt;/code&gt; or &lt;code&gt;target/&lt;/code&gt; instead of starting cold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR checkout&lt;/strong&gt; with &lt;code&gt;wt switch pr:123&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A unique port per worktree&lt;/strong&gt; so multiple dev servers can run side by side.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Yes, if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run more than one AI coding agent at a time.&lt;/li&gt;
&lt;li&gt;Juggle several branches and hate stashing or re-cloning.&lt;/li&gt;
&lt;li&gt;Already use git worktrees and are tired of the long commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few honest caveats. It's a young project, so expect frequent releases and occasional changes. Every worktree is a full copy of your working files, so large repos use more disk space (the cache-copying feature helps, but doesn't remove this). On Windows, &lt;code&gt;wt&lt;/code&gt; clashes with the Windows Terminal command, so it installs as &lt;code&gt;git-wt&lt;/code&gt; instead unless you disable that alias. And if you only ever work on one branch at a time, plain &lt;code&gt;git switch&lt;/code&gt; is all you need.&lt;/p&gt;

&lt;p&gt;If parallel agents are part of your workflow, Worktrunk removes most of the friction of worktrees. Install it, spin up two worktrees, and you'll know within ten minutes whether it sticks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/max-sixty/worktrunk" rel="noopener noreferrer"&gt;https://github.com/max-sixty/worktrunk&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>agents</category>
      <category>git</category>
    </item>
    <item>
      <title>Docling: Turn Messy Documents into Clean Data for Your AI App</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Sat, 19 Sep 2026 20:57:15 +0000</pubDate>
      <link>https://dev.to/arshtechpro/docling-turn-messy-documents-into-clean-data-for-your-ai-app-3gnp</link>
      <guid>https://dev.to/arshtechpro/docling-turn-messy-documents-into-clean-data-for-your-ai-app-3gnp</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;If you've built anything with LLMs, you've hit this wall: your data lives in PDFs, Word files, slide decks, and scanned images. You need clean text to feed a model or a RAG pipeline. Basic PDF-to-text tools give you a jumbled mess: tables collapse into random lines, two-column layouts get read in the wrong order, and headers mix with body text.&lt;/p&gt;

&lt;p&gt;Docling is an open-source Python library built to solve exactly that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Docling is
&lt;/h2&gt;

&lt;p&gt;Docling reads documents and converts them into structured output such as Markdown, HTML, or JSON. It was started by IBM Research Zurich, is now hosted by the LF AI &amp;amp; Data Foundation, and is MIT licensed. It has over 66k stars on GitHub, so it's far from a side project.&lt;/p&gt;

&lt;p&gt;What sets it apart from a plain text extractor is that it tries to &lt;em&gt;understand&lt;/em&gt; the page. It detects layout and reading order, rebuilds tables, and recognizes code blocks, formulas, and images.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it supports
&lt;/h2&gt;

&lt;p&gt;Input formats include PDF, DOCX, PPTX, XLSX, HTML, EPUB, images, LaTeX, email files, and even audio and video (transcribed with speech recognition models). Scanned PDFs are handled with OCR.&lt;/p&gt;

&lt;p&gt;Everything is converted into one internal format called &lt;code&gt;DoclingDocument&lt;/code&gt;, which you can then export as Markdown, HTML, or lossless JSON. That means your downstream code deals with one structure no matter what the input was.&lt;/p&gt;

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

&lt;p&gt;You need Python 3.10 or newer.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Convert a document from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docling https://arxiv.org/pdf/2206.01062
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes a &lt;code&gt;.md&lt;/code&gt; file to your current directory.&lt;/p&gt;

&lt;p&gt;Or use it from Python:&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;docling.document_converter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DocumentConverter&lt;/span&gt;

&lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DocumentConverter&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;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://arxiv.org/pdf/2408.09869&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;result&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="nf"&gt;export_to_markdown&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 it. Local file paths work the same way as URLs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it fits in your stack
&lt;/h2&gt;

&lt;p&gt;Docling has ready-made integrations with LangChain, LlamaIndex, CrewAI, and Haystack, so you can drop it into an existing RAG pipeline as the document loader. It also ships an MCP server for connecting it to AI agents, and an API server (&lt;code&gt;docling-serve&lt;/code&gt;) if you'd rather run it as a service than import it as a library.&lt;/p&gt;

&lt;p&gt;It runs fully locally, which matters if you're handling sensitive documents or working in an air-gapped environment. No data has to leave your machine.&lt;/p&gt;

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

&lt;p&gt;Yes, if any of these describe you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're building a RAG system or chatbot over real-world documents.&lt;/li&gt;
&lt;li&gt;You have PDFs with tables that other tools mangle.&lt;/li&gt;
&lt;li&gt;You need to process many file types without writing a separate parser for each.&lt;/li&gt;
&lt;li&gt;You can't send documents to a third-party API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few honest caveats. Docling uses machine learning models for layout and table detection, so the install is heavier than a lightweight library like &lt;code&gt;pypdf&lt;/code&gt;, and models are downloaded on first run. Processing large PDF batches on CPU can be slow, and a GPU helps a lot. If all you need is raw text from simple, single-column PDFs, a lighter tool will do the job with less overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/docling-project/docling" rel="noopener noreferrer"&gt;https://github.com/docling-project/docling&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>rag</category>
    </item>
    <item>
      <title>Open Source Alternative to Claude Code and Cursor: Meet Cline</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 17 Sep 2026 08:18:39 +0000</pubDate>
      <link>https://dev.to/arshtechpro/open-source-alternative-to-claude-code-and-cursor-meet-cline-5cfi</link>
      <guid>https://dev.to/arshtechpro/open-source-alternative-to-claude-code-and-cursor-meet-cline-5cfi</guid>
      <description>&lt;p&gt;Cline is an open source, autonomous coding agent. Instead of just autocompleting the line you're typing, Cline can read your entire project, plan out a set of changes, edit multiple files, run terminal commands, and check its own work against linter and compiler errors, all with you reviewing and approving each step.&lt;/p&gt;

&lt;p&gt;It started as a VS Code extension (previously known as "Claude Dev"), but it has grown into something bigger. Today, Cline ships as four things built on the same underlying engine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VS Code Extension&lt;/strong&gt; — the original, most widely used form. Install it from the VS Code Marketplace and it sits right in your editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JetBrains Plugin&lt;/strong&gt; — the same experience inside IntelliJ IDEA, PyCharm, WebStorm, GoLand, and the rest of the JetBrains family.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI&lt;/strong&gt; — run Cline directly in your terminal, either as an interactive chat or fully headless for scripts and CI/CD pipelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK&lt;/strong&gt; — a Node.js package (&lt;code&gt;@cline/sdk&lt;/code&gt;) for developers who want to build their own agents, custom tools, or integrations on top of Cline's engine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's licensed under Apache 2.0, and as of this writing has over 67,000 stars and more than 7,000 forks on GitHub, so it has real traction, not just a novelty project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Can It Actually Do?
&lt;/h2&gt;

&lt;p&gt;Here's a breakdown of the core capabilities, in plain terms.&lt;/p&gt;

&lt;h3&gt;
  
  
  It edits code across your whole project
&lt;/h3&gt;

&lt;p&gt;Cline doesn't just look at the file you have open. It reads your project structure, figures out how files relate to each other, and makes coordinated edits across the codebase. While it works, it watches for linter and compiler errors and tries to fix problems like missing imports or type mismatches before you even notice them. Every edit shows up as a reviewable diff, and changes are tracked with checkpoints so you can undo the agent's work if something goes wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  It runs terminal commands
&lt;/h3&gt;

&lt;p&gt;Cline can execute commands directly: installing packages, running build scripts, executing tests, deploying, managing databases. For long-running processes like a dev server, it keeps watching the output in the background and reacts to new errors or crashes as they appear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plan mode and Act mode
&lt;/h3&gt;

&lt;p&gt;This is one of Cline's more distinctive features. In &lt;strong&gt;Plan mode&lt;/strong&gt;, Cline explores your code, asks clarifying questions, and proposes a strategy before touching anything. Once you're happy with the plan, you switch to &lt;strong&gt;Act mode&lt;/strong&gt; and it executes. By default, every file edit and command needs your approval — though you can flip on auto-approve if you want it to run more autonomously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom rules and skills
&lt;/h3&gt;

&lt;p&gt;You can define project-specific rules in &lt;code&gt;.clinerules&lt;/code&gt; files: coding standards, architecture conventions, deployment steps, testing requirements. These are picked up automatically across the CLI, VS Code extension, and JetBrains plugin, so the agent behaves consistently with your team's conventions rather than guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  You're not locked into one AI model
&lt;/h3&gt;

&lt;p&gt;This is a big differentiator. Cline doesn't force you onto a single provider. You can plug in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anthropic (Claude Opus, Sonnet, Haiku)&lt;/li&gt;
&lt;li&gt;OpenAI (GPT series)&lt;/li&gt;
&lt;li&gt;Google (Gemini series)&lt;/li&gt;
&lt;li&gt;OpenRouter (200+ models)&lt;/li&gt;
&lt;li&gt;AWS Bedrock, Azure, GCP Vertex&lt;/li&gt;
&lt;li&gt;Cerebras, Groq (fast inference)&lt;/li&gt;
&lt;li&gt;Ollama or LM Studio for local models&lt;/li&gt;
&lt;li&gt;Any OpenAI-compatible endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You bring your own API key, and you decide what you're paying for and which model fits the task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensibility: plugins and MCP servers
&lt;/h3&gt;

&lt;p&gt;Using the SDK, you can register custom tools and lifecycle hooks for logging, auditing, policy enforcement, or domain-specific capabilities. Cline also supports &lt;a href="https://github.com/modelcontextprotocol" rel="noopener noreferrer"&gt;MCP (Model Context Protocol)&lt;/a&gt; servers, so it can connect to databases, call APIs, manage cloud infrastructure, or use community-built tools. You can even ask Cline to write a new custom tool on the fly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-agent teams and scheduled agents
&lt;/h3&gt;

&lt;p&gt;Newer additions let you coordinate multiple agents on a single task, with a coordinator agent delegating subtasks to specialists, and state persisting across sessions. You can also schedule agents to run on a cron schedule for recurring work like daily PR summaries or weekly dependency checks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chat with it from Slack, Telegram, Discord, and more
&lt;/h3&gt;

&lt;p&gt;Cline can connect to messaging platforms so you can hand it tasks from Slack, Telegram, Discord, Google Chat, WhatsApp, or Linear, with each conversation thread mapped to a full agent session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Headless mode for CI/CD
&lt;/h3&gt;

&lt;p&gt;For automation, Cline can run with zero interaction: pipe input in, get JSON output back, and chain it into scripts or pipelines. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cline &lt;span class="s2"&gt;"Run tests and fix any failures"&lt;/span&gt;
git diff origin/main | cline &lt;span class="s2"&gt;"Review these changes for issues"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Do You Get Started?
&lt;/h2&gt;

&lt;p&gt;For the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; cline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the editor experience, install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" rel="noopener noreferrer"&gt;VS Code extension&lt;/a&gt; or the &lt;a href="https://plugins.jetbrains.com/plugin/28247-cline" rel="noopener noreferrer"&gt;JetBrains plugin&lt;/a&gt;, then connect your API key from whichever model provider you want to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is It Worth Trying?
&lt;/h2&gt;

&lt;p&gt;Short answer: yes, especially if any of the following sound like you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try Cline if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want an agent that can make autonomous, multi-file changes across a real codebase, not just single-line suggestions.&lt;/li&gt;
&lt;li&gt;You want to choose your own model and control your own costs, rather than being locked into one vendor's bundled pricing.&lt;/li&gt;
&lt;li&gt;You already live in VS Code or a JetBrains IDE and don't want to switch to a different editor entirely.&lt;/li&gt;
&lt;li&gt;You want to inspect, extend, or audit the tool itself, since it's fully open source under Apache 2.0.&lt;/li&gt;
&lt;li&gt;You want the same agent core available as a CLI for scripting, a plugin for your editor, and an SDK for building your own tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Think twice, or pair it with something else, if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want a fully polished, all-in-one AI-native editor experience. Tools like Cursor offer a more integrated, purpose-built interface with fast inline completions, and many developers report an easier on-ramp for beginners.&lt;/li&gt;
&lt;li&gt;You'd rather pay a flat monthly fee and not think about token costs. Cline's "bring your own key" model means your spend depends on which model you use and how much you run it, and heavy usage can add up.&lt;/li&gt;
&lt;li&gt;You want something with zero setup. Cline requires you to get an API key from a provider and configure it, which is a small extra step compared to tools with built-in, bundled access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Compares to Other Agents
&lt;/h2&gt;

&lt;p&gt;It's worth being clear-eyed about where Cline sits in the current landscape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cline vs Cursor&lt;/strong&gt;: Cursor is a standalone, AI-native editor (a VS Code fork) with a bundled model and a smoother out-of-the-box experience. Cline is a VS Code/JetBrains extension plus CLI and SDK, open source, and model-agnostic. Many developers actually run both: Cursor for fast in-editor completions, an agent like Cline or Claude Code for larger autonomous, multi-file work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cline vs Claude Code&lt;/strong&gt;: Claude Code is Anthropic's own terminal-first agent, tightly built around Claude models. Cline offers a similar terminal and autonomous-agent experience but lets you swap in any model provider, and it also gives you a full IDE extension and SDK, which Claude Code doesn't offer in the same way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither of these makes Cline "better" or "worse" outright. It's a different set of trade-offs: openness and model flexibility versus the tighter polish of a closed, single-vendor product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/cline/cline" rel="noopener noreferrer"&gt;github.com/cline/cline&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
      <category>programming</category>
    </item>
    <item>
      <title>BrewUI: A First Look at Homebrew's Official macOS GUI</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Wed, 16 Sep 2026 13:44:53 +0000</pubDate>
      <link>https://dev.to/arshtechpro/brewui-a-first-look-at-homebrews-official-macos-gui-3fk2</link>
      <guid>https://dev.to/arshtechpro/brewui-a-first-look-at-homebrews-official-macos-gui-3fk2</guid>
      <description>&lt;p&gt;If you use a Mac for development, you almost certainly have Homebrew installed. You type &lt;code&gt;brew install something&lt;/code&gt;, wait a few seconds, and move on with your day.&lt;/p&gt;

&lt;p&gt;But not everyone who needs Homebrew is comfortable in a terminal. Designers, data folks, students, and plenty of developers early in their careers often get told "just install it with brew" and then get stuck.&lt;/p&gt;

&lt;p&gt;The Homebrew team is working on an answer to that: &lt;strong&gt;BrewUI&lt;/strong&gt;, an official, native macOS app for managing Homebrew packages. The project lives at &lt;a href="https://github.com/Homebrew/BrewUI" rel="noopener noreferrer"&gt;github.com/Homebrew/BrewUI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article walks through what BrewUI is, the ideas behind it, and how its architecture works, in plain terms.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heads up:&lt;/strong&gt; BrewUI is in early development. The team describes the current phase as building the app foundation. Treat everything here as a look at a project in progress, not a finished product you can download today.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;BrewUI is a graphical front end for Homebrew. Instead of typing commands, you can search for packages, install them, update them, and remove them through a regular Mac app window.&lt;/p&gt;

&lt;p&gt;The key word is &lt;strong&gt;official&lt;/strong&gt;. There have been third-party Homebrew GUIs over the years, but this one is maintained under the Homebrew organization itself.&lt;/p&gt;

&lt;p&gt;The stated goal is to let people who avoid the command line safely discover and manage packages, without the app ever hiding what Homebrew is actually doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea: transparency
&lt;/h2&gt;

&lt;p&gt;Most GUIs wrap a tool and try to make you forget the tool exists. BrewUI takes the opposite approach.&lt;/p&gt;

&lt;p&gt;The design rules say the app should always show the &lt;strong&gt;exact command&lt;/strong&gt; it is running. If you click "Install" on a package, you should be able to see the real &lt;code&gt;brew&lt;/code&gt; command behind that button, along with its output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Homebrew stays the source of truth
&lt;/h2&gt;

&lt;p&gt;BrewUI does not reimplement Homebrew or reach into its internals. It gets data in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;brew&lt;/code&gt; command line tool&lt;/strong&gt;, run as a subprocess (the same way you would run it yourself).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;a href="https://formulae.brew.sh/docs/api/" rel="noopener noreferrer"&gt;Homebrew JSON API&lt;/a&gt;&lt;/strong&gt; at &lt;code&gt;formulae.brew.sh&lt;/code&gt;, which provides package metadata.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It also does not bundle Homebrew. If Homebrew is not installed, the app is meant to detect that and degrade gracefully rather than crash. To find &lt;code&gt;brew&lt;/code&gt;, it checks the two standard locations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/homebrew/bin/brew   &lt;span class="c"&gt;# Apple Silicon&lt;/span&gt;
/usr/local/bin/brew      &lt;span class="c"&gt;# Intel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the app simple: Homebrew does the real work, and BrewUI presents it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech stack at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;Swift 6.0 with strict concurrency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;SwiftUI (AppKit only when SwiftUI cannot do the job)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@Observable&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, actors for shared mutable state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;Swift Package Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;macOS only, with macOS Tahoe 26 as the main target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you have been meaning to see what a modern, "all in" Swift 6 macOS project looks like, this repository is a good real-world example.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the architecture works
&lt;/h2&gt;

&lt;p&gt;Here is the part that is most interesting for developers. BrewUI follows a layered design. A user action flows down through the layers 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;View  -&amp;gt;  ViewModel  -&amp;gt;  Repository or Interactor  -&amp;gt;  Service  -&amp;gt;  brew CLI / JSON API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break that down with a simple example: showing a list of installed packages and letting you upgrade one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Views
&lt;/h3&gt;

&lt;p&gt;SwiftUI views are kept thin. They display state and forward user actions. A view knows that a button was tapped; it does not know how to upgrade a package.&lt;/p&gt;

&lt;h3&gt;
  
  
  ViewModels
&lt;/h3&gt;

&lt;p&gt;The ViewModel holds presentation state, such as "is this list loading?" or "what text should this label show?". It turns domain data into something the UI can display, and passes real work further down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repositories
&lt;/h3&gt;

&lt;p&gt;A Repository is about &lt;strong&gt;reading data from a source&lt;/strong&gt;. For example, getting the list of installed packages from &lt;code&gt;brew list&lt;/code&gt; output, or package details from the JSON API.&lt;/p&gt;

&lt;p&gt;The benefit: the rest of the app does not care where the data came from. You could swap in a mock repository for tests and nothing above it would change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactors
&lt;/h3&gt;

&lt;p&gt;An Interactor represents &lt;strong&gt;one specific use case&lt;/strong&gt;, such as running &lt;code&gt;brew doctor&lt;/code&gt;. It is not a generic "fetch everything" layer; it is a single, focused action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;Services are the infrastructure at the edge of the app: actually launching the &lt;code&gt;brew&lt;/code&gt; process, making HTTP requests, and so on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Models
&lt;/h3&gt;

&lt;p&gt;Plain domain types (like a package) shared across layers. They intentionally stay free of UI details, so the same model works for a list row, a detail page, or a test.&lt;/p&gt;

&lt;p&gt;If you know MVVM and Clean Architecture, this will feel familiar. The project describes it as a lightweight MVVM with a coordinator style, guided by Clean Architecture ideas, and it explicitly prefers the smallest pattern that solves the current problem rather than building everything up front.&lt;/p&gt;

&lt;h2&gt;
  
  
  The command center: why brew commands run one at a time
&lt;/h2&gt;

&lt;p&gt;One detail worth calling out is the &lt;strong&gt;command center&lt;/strong&gt;, an actor named &lt;code&gt;BrewCommandCenter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Homebrew does not like it when you run multiple commands that change your system at the same time. Picture a user clicking "Upgrade" on three packages in quick succession. In a terminal you would naturally run them one after another. A GUI needs to enforce that on your behalf.&lt;/p&gt;

&lt;p&gt;The command center:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serializes&lt;/strong&gt; any command that changes the system, so they run in order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracks the state&lt;/strong&gt; of each operation (in progress, failed, and so on), so every part of the UI can show accurate status.&lt;/li&gt;
&lt;li&gt;Runs small, dedicated command types for each mutating action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reading data, like parsing &lt;code&gt;brew list&lt;/code&gt; or &lt;code&gt;brew info&lt;/code&gt;, is not its job. That stays in the repositories. This separation keeps "things that change your machine" in one controlled place.&lt;/p&gt;

&lt;p&gt;Using a Swift &lt;code&gt;actor&lt;/code&gt; here is a nice fit: actors guarantee only one task touches their state at a time, which is exactly the property you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing for tools that change
&lt;/h2&gt;

&lt;p&gt;BrewUI depends on two things it does not control: the text output of &lt;code&gt;brew&lt;/code&gt; and the shape of the JSON API. Both can change between Homebrew releases.&lt;/p&gt;

&lt;p&gt;The project handles that with a defensive mindset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLI output is treated as unstable.&lt;/strong&gt; Parsers are expected to be tolerant and have fallbacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON decoding is resilient.&lt;/strong&gt; Unknown or missing fields should never crash the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands are async and cancellable&lt;/strong&gt;, with output streamed or preserved for logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is good advice for any app that wraps a command line tool, not just this one.&lt;/p&gt;

&lt;p&gt;Check it out here: &lt;a href="https://github.com/Homebrew/BrewUI" rel="noopener noreferrer"&gt;github.com/Homebrew/BrewUI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>homebew</category>
      <category>swift</category>
      <category>opensource</category>
      <category>macos</category>
    </item>
    <item>
      <title>What 100+ Leaked System Prompts Teach You About Prompt Engineering</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Tue, 15 Sep 2026 22:39:31 +0000</pubDate>
      <link>https://dev.to/arshtechpro/what-ai-chatbots-are-told-before-you-type-a-developers-guide-to-the-systemprompts-1oei</link>
      <guid>https://dev.to/arshtechpro/what-ai-chatbots-are-told-before-you-type-a-developers-guide-to-the-systemprompts-1oei</guid>
      <description>&lt;p&gt;Every time you open ChatGPT, Claude, Gemini, or an AI coding tool like Cursor, the model has already read a long set of instructions before your first message arrives. You never see those instructions, but they shape almost everything about how the assistant behaves: its tone, its formatting habits, which tools it reaches for, and what it refuses to do.&lt;/p&gt;

&lt;p&gt;The GitHub repository &lt;a href="https://github.com/asgeirtj/system_prompts_leaks" rel="noopener noreferrer"&gt;asgeirtj/system_prompts_leaks&lt;/a&gt; collects those hidden instructions in one place.&lt;/p&gt;

&lt;p&gt;This article explains what the repo is, how it is organized, and, most importantly, what you as a developer can take away from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, what is a system prompt?
&lt;/h2&gt;

&lt;p&gt;If you have used an LLM API, you have already written one. A chat request is usually split into roles. The &lt;code&gt;system&lt;/code&gt; message sets the rules, and the &lt;code&gt;user&lt;/code&gt; messages are the conversation.&lt;/p&gt;

&lt;p&gt;Here is a minimal example using the OpenAI-style message format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a support bot for Acme Inc. Answer only questions about Acme products. Keep answers under 100 words.&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;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How do I reset my password?&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;The end user only sees the second message and the reply. The first message is invisible to them, but it steers the whole response.&lt;/p&gt;

&lt;p&gt;Commercial products do exactly the same thing, just at a much bigger scale. Instead of two sentences, their system prompts can run to thousands of words covering personality, formatting rules, tool definitions, safety policies, and product-specific behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the repo contains
&lt;/h2&gt;

&lt;p&gt;The repo is a large, organized collection of these production system prompts, captured from real products. Each prompt is stored as a Markdown file, grouped into folders by company.&lt;/p&gt;

&lt;p&gt;The main folders include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic&lt;/strong&gt;: Claude.ai chat prompts for several model versions, Claude Code (including subagents, slash commands, and injected reminders), and integrations such as Claude in Chrome, Excel, Word, and PowerPoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI&lt;/strong&gt;: ChatGPT prompts across model versions, Codex (including plan mode and computer use), voice modes, memory, and older tool prompts like Canvas and the Python tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google&lt;/strong&gt;: Gemini app prompts, Gemini CLI, NotebookLM, Jules, AI Studio, and Google Search AI Mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;xAI&lt;/strong&gt;: Grok versions, personas, and safety instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft&lt;/strong&gt;: GitHub Copilot, the VS Code Copilot agent, and Copilot CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Others&lt;/strong&gt;: Cursor, Perplexity, Meta AI, Mistral, DeepSeek, Kimi, Qwen, Notion AI, and a "Misc" folder with tools like Warp, Zed, Docker's Gordon, Raycast, and Kagi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also an interesting note in the GLM folder: the maintainer documents that GLM appears to serve no system prompt at all, which is a useful data point in itself.&lt;/p&gt;

&lt;p&gt;The README has a "Recently Updated" table at the top, so it is easy to see which products have fresh captures. The repo is released under the CC0-1.0 license.&lt;/p&gt;

&lt;p&gt;It has also been picked up outside the developer world. The README points to a Washington Post interactive piece (May 2026) and a data dashboard from CEPS' AI World project (July 2026), both built on files from the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  How are these prompts obtained?
&lt;/h2&gt;

&lt;p&gt;Mostly through prompt extraction: asking the model, in one way or another, to repeat the text it was given before the conversation started. The banner image on the repo shows exactly this kind of request.&lt;/p&gt;

&lt;p&gt;This works because a system prompt is just text sitting in the model's context window. The model can read it, so with the right phrasing it can often be convinced to write it back out.&lt;/p&gt;

&lt;p&gt;A few caveats worth keeping in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Captures are not official.&lt;/strong&gt; These are not documents published by the vendors, so treat them as snapshots rather than a guaranteed source of truth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts change constantly.&lt;/strong&gt; Vendors update them frequently, sometimes weekly. A file might describe last month's behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some text is dynamic.&lt;/strong&gt; Dates, user locations, enabled tools, and feature flags are often injected at runtime, so two users can receive slightly different prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Models can hallucinate.&lt;/strong&gt; An extraction can include invented or garbled sections, which is why cross-checking multiple captures matters.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why developers should care
&lt;/h2&gt;

&lt;p&gt;You do not need to be building a chatbot to get value from this repo. Here are the practical lessons.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. It is a free masterclass in production prompt engineering
&lt;/h3&gt;

&lt;p&gt;Most prompt engineering tutorials show short, toy examples. These files show how teams with large budgets actually structure instructions that serve millions of users.&lt;/p&gt;

&lt;p&gt;When you read through a few of them, patterns jump out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structure with tags or headers.&lt;/strong&gt; Many prompts group rules into clearly labeled sections (formatting, tools, safety, product info) instead of one long paragraph. This makes them easier for the model to follow and easier for humans to maintain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain the why, not only the rule.&lt;/strong&gt; Good prompts often give a short reason behind an instruction. Models generalize better when they understand the intent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use examples.&lt;/strong&gt; Prompts frequently include sample requests with good and bad responses, which is one of the most reliable ways to pin down behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be explicit about edge cases.&lt;/strong&gt; A lot of text is spent on situations that go wrong in practice: ambiguous requests, conflicting instructions, stale information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your own system prompt is three lines long and your app behaves inconsistently, comparing it against these files is a quick way to see what you are missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. It shows how tools and agents are wired up
&lt;/h3&gt;

&lt;p&gt;The coding agent prompts (Claude Code, Codex, Copilot agent, Cursor, Gemini CLI) are especially useful if you are building agentic workflows. They show how vendors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Describe each tool and when to use it&lt;/li&gt;
&lt;li&gt;Tell the model to plan before acting&lt;/li&gt;
&lt;li&gt;Handle file edits, terminal commands, and verification steps&lt;/li&gt;
&lt;li&gt;Split work across subagents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reading two or three of these side by side gives you a good mental model of how modern AI agents are designed, without having to reverse-engineer them yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. It explains "weird" model behavior
&lt;/h3&gt;

&lt;p&gt;Ever wondered why an assistant keeps avoiding bullet points, insists on searching the web for a simple question, or refuses to reproduce song lyrics? The answer is often sitting right in the system prompt.&lt;/p&gt;

&lt;p&gt;Knowing this helps you debug your own integrations. If you use a consumer app and the API and notice they behave differently, the system prompt is usually the reason. The API gives you a much cleaner slate.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. It is a security lesson: your system prompt is not a secret
&lt;/h3&gt;

&lt;p&gt;This is the most important takeaway. If the largest AI companies in the world cannot keep their system prompts private, your app will not be able to either.&lt;/p&gt;

&lt;p&gt;Treat your system prompt as &lt;strong&gt;public by default&lt;/strong&gt;. That means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do NOT put in a system prompt:
- API keys, tokens, or passwords
- Internal URLs or database connection strings
- Private customer data
- Business logic you would be embarrassed to see on GitHub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And do not rely on the prompt as your only security boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad: trusting the prompt to enforce access control&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Never reveal other users' orders.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Better: enforce it in your backend before data reaches the model&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// the model never sees other users' data&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule of thumb: the model should only ever have access to data the current user is already allowed to see. If a clever user extracts or bypasses the prompt, nothing sensitive should leak.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. It helps you compare vendors
&lt;/h3&gt;

&lt;p&gt;Because so many products are in one place, you can compare how different companies approach the same problem, such as how they format answers, how cautious they are, or how they describe web search. That is useful context when choosing a model or provider for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to explore it efficiently
&lt;/h2&gt;

&lt;p&gt;The repo is large, so here is a practical way in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with the product you use most.&lt;/strong&gt; If you live in Cursor or Copilot, open that file first. It will immediately explain some behavior you have noticed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read one chat prompt and one agent prompt.&lt;/strong&gt; For example, a ChatGPT or Claude chat prompt, then a coding agent prompt. The contrast is instructive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clone it and search locally.&lt;/strong&gt; Grep across vendors to see how each one handles a topic.
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;span class="c"&gt;# See how different products talk about tool usage&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-ril&lt;/span&gt; &lt;span class="s2"&gt;"tool"&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.md"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;

&lt;span class="c"&gt;# Compare formatting rules across vendors&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-ri&lt;/span&gt; &lt;span class="s2"&gt;"markdown"&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.md"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; | less
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Borrow patterns, not text.&lt;/strong&gt; Use the structure and techniques in your own prompts, but write instructions that fit your product rather than copying a vendor's prompt wholesale.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Repo: &lt;a href="https://github.com/asgeirtj/system_prompts_leaks" rel="noopener noreferrer"&gt;github.com/asgeirtj/system_prompts_leaks&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
      <category>programming</category>
    </item>
    <item>
      <title>iPhone Duo for iOS Developers: What Actually Changes in Your Swift Code</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Wed, 09 Sep 2026 21:16:11 +0000</pubDate>
      <link>https://dev.to/arshtechpro/iphone-duo-for-ios-developers-what-actually-changes-in-your-swift-code-5gc5</link>
      <guid>https://dev.to/arshtechpro/iphone-duo-for-ios-developers-what-actually-changes-in-your-swift-code-5gc5</guid>
      <description>&lt;p&gt;Apple announced the &lt;strong&gt;iPhone Duo&lt;/strong&gt; today — its first foldable iPhone. A 5.4-inch outer display, a 7.6-inch inner display when you open it, ships with iOS 27.x.&lt;/p&gt;

&lt;p&gt;The marketing story is the hardware. The developer story is that &lt;strong&gt;a lot of assumptions baked into iPhone apps since 2007 just stopped being true.&lt;/strong&gt; There is now more than one screen. The screen can change shape while your app is running. The safe area is no longer symmetric. And "portrait only" doesn't mean what you think it means anymore.&lt;/p&gt;

&lt;p&gt;The good news: if you've been doing adaptive layout properly for iPad, most of this is a short afternoon. If your app hardcodes screen sizes and branches on orientation, you have some work to do.&lt;/p&gt;

&lt;p&gt;Here's the practical version.&lt;/p&gt;




&lt;h2&gt;
  
  
  First: what happens if you do nothing?
&lt;/h2&gt;

&lt;p&gt;Your app still runs. It doesn't crash, it doesn't get pulled. But how much of the screen you get depends on which SDK you last built against:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Built with&lt;/th&gt;
&lt;th&gt;Inner display behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Older SDK (no rebuild)&lt;/td&gt;
&lt;td&gt;Runs, but letterboxed — your app keeps its old aspect ratio, with black bars either side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS 27 SDK&lt;/td&gt;
&lt;td&gt;Extends left of the status bar, avoiding the camera area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS 27.1 SDK&lt;/td&gt;
&lt;td&gt;Full edge-to-edge, and standard nav/toolbar buttons lay out vertically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So step zero is genuinely just: &lt;strong&gt;rebuild with Xcode 27.1.&lt;/strong&gt; That alone moves you from "obviously not updated" to "fine." Everything below is the difference between "fine" and "good."&lt;/p&gt;




&lt;h2&gt;
  
  
  The four poses you now have to support
&lt;/h2&gt;

&lt;p&gt;This is the mental model shift. It's not portrait vs landscape anymore. It's:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Closed, portrait&lt;/strong&gt; — behaves like a normal iPhone&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Closed, landscape&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open, vertical&lt;/strong&gt; (tall, near-square)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open, horizontal&lt;/strong&gt; (wide)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Plus the in-between states: partially folded like a book, or propped up in a tent on a table. Your layout has to survive all of them, and it has to survive &lt;em&gt;transitions&lt;/em&gt; between them while state is live.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #1: Size classes, not orientation
&lt;/h2&gt;

&lt;p&gt;This is the single most important line in Apple's guidance, and it will break the most apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The inner display doesn't honor your supported interface orientations.&lt;/strong&gt; If your app branches layout on &lt;code&gt;UIDevice.orientation&lt;/code&gt; or &lt;code&gt;supportedInterfaceOrientations&lt;/code&gt;, that logic is now lying to you.&lt;/p&gt;

&lt;p&gt;Use size classes instead — they describe &lt;em&gt;the space you have&lt;/em&gt;, which is the thing you actually care about:&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;// SwiftUI&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView&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;horizontalSizeClass&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;hSize&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;verticalSizeClass&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;vSize&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;hSize&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regular&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;WideLayout&lt;/span&gt;&lt;span class="p"&gt;()&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="kt"&gt;CompactLayout&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UIKit&lt;/span&gt;
&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;traitCollectionDidChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UITraitCollection&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;traitCollectionDidChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous&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;isWide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;traitCollection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;horizontalSizeClass&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regular&lt;/span&gt;
    &lt;span class="c1"&gt;// reconfigure&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What to expect on device:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Outer display&lt;/strong&gt; → same size classes as any other iPhone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inner display&lt;/strong&gt; → &lt;strong&gt;regular in both dimensions&lt;/strong&gt;, which is what leaves room for sidebars and two-column layouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That second row is the one worth internalizing. The inner display is, as far as your layout code is concerned, iPad-shaped.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #2: Stop referencing the main screen
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;UIScreen.main&lt;/code&gt; is ambiguous on a two-display device, and Apple has said it's heading for deprecation. There is no longer one 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="c1"&gt;// ❌ Which screen? Nobody knows.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIScreen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIScreen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bounds&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Ask the trait collection&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;traitCollection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;displayScale&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Or get the screen dynamically from the window scene&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;windowScene&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For layout size, prefer the scene's bounds or the environment over anything screen-derived. Do a project-wide search for &lt;code&gt;UIScreen.main&lt;/code&gt; right now — it's usually a five-minute fix and it's the most likely source of weird bugs.&lt;/p&gt;

&lt;p&gt;While you're in there, &lt;code&gt;ConcentricRectangle&lt;/code&gt; (SwiftUI) and &lt;code&gt;UICornerConfiguration&lt;/code&gt; (UIKit), introduced in iOS 26, will match the actual screen corner radius instead of your hardcoded &lt;code&gt;cornerRadius: 12&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #3: Safe areas are now asymmetric
&lt;/h2&gt;

&lt;p&gt;On a normal iPhone, the left and right insets match, so a lot of code does 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;// ❌ Assumes both sides are equal&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;usableWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&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="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;left&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On iPhone Duo, safe areas and layout margins are &lt;strong&gt;frequently asymmetric&lt;/strong&gt; — the camera is on one side, and in Split View your app occupies half the display with different insets on each edge. Handle each side independently:&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;// ✅&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;usableWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&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="nf"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The general rule Apple repeats: &lt;strong&gt;interactive foreground content stays inside the safe area; background artwork extends past it.&lt;/strong&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="c1"&gt;// SwiftUI&lt;/span&gt;
&lt;span class="kt"&gt;ZStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;BackgroundArtwork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ignoresSafeArea&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// background: bleed&lt;/span&gt;
    &lt;span class="kt"&gt;ControlsView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// foreground: respects safe area by default&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Change #4: Reserved regions (the hinge and the cameras)
&lt;/h2&gt;

&lt;p&gt;This is a genuinely new concept. The device has physical features that carve up the display: the &lt;strong&gt;hinge&lt;/strong&gt; and the &lt;strong&gt;cameras&lt;/strong&gt;. Apple calls these &lt;em&gt;reserved regions&lt;/em&gt;, and you can query them.&lt;/p&gt;

&lt;p&gt;Two kinds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.division&lt;/code&gt;&lt;/strong&gt; — the fold. It splits a larger area into smaller ones. It's only &lt;em&gt;active&lt;/em&gt; when the device is actually folded; when flat it has zero width and is inactive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.occlusion&lt;/code&gt;&lt;/strong&gt; — something sitting on top of your content. This is the under-display FaceTime camera.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SwiftUI&lt;/span&gt;
&lt;span class="kt"&gt;GeometryReader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;proxy&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;folds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reservedRegions&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;division&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;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;folds&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;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;MyLayout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;avoiding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;frames&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UIKit&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;folds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reservedRegions&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;division&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;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;folds&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;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inactive regions are excluded by default. Ask for them when you want to make a &lt;em&gt;structural&lt;/em&gt; decision that shouldn't flip-flop as the user opens and closes the device — like "always use an even number of grid columns so nothing lands on the fold":&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;folds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reservedRegions&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;division&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="n"&gt;includeInactive&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;When to reach for this:&lt;/strong&gt; custom, manually laid-out controls. Standard containers — &lt;code&gt;NavigationStack&lt;/code&gt;, &lt;code&gt;NavigationSplitView&lt;/code&gt;, &lt;code&gt;TabView&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;ScrollView&lt;/code&gt; — already adapt to the fold for free, and the system automatically repositions alerts, action sheets, menus and popovers around reserved regions. Don't reimplement that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design note that's easy to miss:&lt;/strong&gt; continuously scrolling content (articles, feeds) should &lt;em&gt;not&lt;/em&gt; jump around to avoid the fold. Displacement is for discrete elements — a button, a control cluster, a container — not for a reading surface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #5: Arrangements — a new layout container
&lt;/h2&gt;

&lt;p&gt;New in iOS 27.1. An &lt;code&gt;ArrangementView&lt;/code&gt; sits between your navigation container and your content, takes a &lt;strong&gt;primary&lt;/strong&gt; and &lt;strong&gt;secondary&lt;/strong&gt; view, and decides how to place them based on size classes, aspect ratio, and any active division regions.&lt;/p&gt;

&lt;p&gt;Think Podcasts: now-playing view plus transcript.&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;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;NavigationStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ArrangementView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;PlayerView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;UpNextView&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;arrangementViewStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&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 styles:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.split&lt;/code&gt;&lt;/strong&gt; — divides the available bounds between the two views. Horizontally when wider than tall, vertically when taller. Constrain it if you only want one axis:&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;arrangementViewStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;horizontal&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;&lt;code&gt;.overlay&lt;/code&gt;&lt;/strong&gt; — prefers stacking content above/below, and moves to side-by-side as the device folds. Read the Z index to adapt the overlaid 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;UpNextView&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;overlayArrangementZIndex&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;zIndex&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;UpNextList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;minimized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;zIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UIKit equivalent:&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;arrangement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIArrangementViewController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;arrangement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setViewController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerVC&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;primary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;arrangement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setViewController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upNextVC&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;secondary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;arrangement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateArrangement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;horizontal&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;nav&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UINavigationController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;rootViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;arrangement&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;Picking one:&lt;/strong&gt; if your existing layout is an &lt;code&gt;HStack&lt;/code&gt;/&lt;code&gt;VStack&lt;/code&gt;, that's split. If it's a &lt;code&gt;ZStack&lt;/code&gt;, that's overlay. Otherwise — overlay when there's a clear foreground/background relationship and partially obscuring the background is acceptable; split when it's main/detail and neither side should be covered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two gotchas:&lt;/strong&gt; &lt;code&gt;ArrangementView&lt;/code&gt; provides no navigation infrastructure, so don't nest a &lt;code&gt;NavigationSplitView&lt;/code&gt; inside one. And don't put one inside a &lt;code&gt;List&lt;/code&gt; or &lt;code&gt;ScrollView&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #6: The hinge API
&lt;/h2&gt;

&lt;p&gt;You can read the hinge directly. &lt;code&gt;onHingeChange&lt;/code&gt; in SwiftUI, &lt;code&gt;UIHingeInteraction&lt;/code&gt; in UIKit. Both give you a coarse status (closed / partially open / fully open) and a continuous angle.&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;InstrumentView&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;@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;pitchBend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;GuitarView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;pitchBend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pitchBend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onHingeChange&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&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="c1"&gt;// nil hinge == device doesn't have one. Always check.&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;hinge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hinge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;hinge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partiallyOpen&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;pitchBend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;pitchBend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bend&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;hinge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;angle&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;That guard is not optional politeness — your app runs on every other iPhone too, where &lt;code&gt;context.hinge&lt;/code&gt; is nil.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important boundary:&lt;/strong&gt; the hinge API is for &lt;em&gt;interactions and effects&lt;/em&gt; — a whammy bar, a parallax, a camera shutter that responds to the fold. It is &lt;strong&gt;not&lt;/strong&gt; for layout. Use arrangements and reserved regions for layout. If you find yourself computing frames from &lt;code&gt;hinge.angle&lt;/code&gt;, you're on the wrong API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #7: Multiple scenes and Split View
&lt;/h2&gt;

&lt;p&gt;Two apps side by side on iPhone, for the first time. Every app participates whether it opts in or not.&lt;/p&gt;

&lt;p&gt;If you already support resizing on iPad or iPhone mirroring, you're most of the way there — same tools, size classes and scene geometry.&lt;/p&gt;

&lt;p&gt;For multiple windows of &lt;em&gt;your own&lt;/em&gt; app, iPhone Duo is the first iPhone to support it, and apps that already do this on iPad get it automatically. One rule to know: &lt;strong&gt;new windows can only be created on the inner display&lt;/strong&gt;, never the outer one. So handle the failure case:&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;// Hides itself automatically when new windows aren't available&lt;/span&gt;
&lt;span class="kt"&gt;UIWindowSceneActivation&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;p&gt;And actually handle the error path when requesting a scene, rather than assuming it succeeds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change #8: Scene accessories (the fun one)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Scene accessories&lt;/strong&gt; let your app put content on &lt;em&gt;both displays at once&lt;/em&gt;. Main UI inside, supplementary content outside.&lt;/p&gt;

&lt;p&gt;The headline case is &lt;code&gt;CameraCaptureAccessory&lt;/code&gt;, available when your app is full screen on the inner display with an active camera session. The obvious use: showing your subject their own framing on the outer display while you shoot. Or a teleprompter:&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;CameraRootView&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;@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;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TeleprompterModel&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;CameraView&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sceneAccessory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;CameraCaptureAccessory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&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;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;TeleprompterView&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="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onAvailabilityChange&lt;/span&gt; &lt;span class="p"&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;isAvailable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$0&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;toolbar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;TeleprompterToggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&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;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disabled&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;isAvailable&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 system controls availability dynamically — closing the device takes it away — so wire up &lt;code&gt;onAvailabilityChange&lt;/code&gt; and disable your UI accordingly instead of letting users tap into nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing this without a $1,999 device
&lt;/h2&gt;

&lt;p&gt;Xcode 27.1 is out now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;iPhone Duo simulator via Device Hub&lt;/strong&gt;, with on-screen controls to open, close, rotate and fold. This is how you'll actually verify the four poses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App Resizability&lt;/strong&gt; — the app modernization skill from "Modernize your UIKit app" at WWDC26, renamed in Xcode 27.1, now covering SwiftUI and iPhone Duo.&lt;/li&gt;
&lt;li&gt;Test Split View explicitly. Half-width plus asymmetric insets is where most layout bugs show up.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;p&gt;Rough order of effort-to-payoff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Rebuild with the iOS 27.1 SDK&lt;/li&gt;
&lt;li&gt;[ ] Grep for &lt;code&gt;UIScreen.main&lt;/code&gt; and replace it&lt;/li&gt;
&lt;li&gt;[ ] Replace orientation checks with size class checks&lt;/li&gt;
&lt;li&gt;[ ] Fix any &lt;code&gt;safeAreaInsets.left * 2&lt;/code&gt; style symmetry assumptions&lt;/li&gt;
&lt;li&gt;[ ] Move custom navigation to &lt;code&gt;NavigationSplitView&lt;/code&gt; / &lt;code&gt;TabView&lt;/code&gt;; consider &lt;code&gt;.defaultTabBarPlacement(.sidebar)&lt;/code&gt; on the inner display&lt;/li&gt;
&lt;li&gt;[ ] Run every screen through all four poses in the simulator&lt;/li&gt;
&lt;li&gt;[ ] Audit centered layouts — would a two-column layout be better?&lt;/li&gt;
&lt;li&gt;[ ] Adopt &lt;code&gt;ArrangementView&lt;/code&gt; for custom split/overlay layouts&lt;/li&gt;
&lt;li&gt;[ ] Adopt reserved regions for your highest-priority hand-laid-out controls&lt;/li&gt;
&lt;li&gt;[ ] Consider the hinge API and scene accessories if your app has a reason to use them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first four are cheap and prevent embarrassment. The rest are where the actual opportunity is — the Duo is going to make it extremely obvious to users which apps got attention and which didn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;Apple's Tech Talks for the Duo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/videos/play/tech-talks/111461/" rel="noopener noreferrer"&gt;Prepare your app for iPhone Duo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>FreeLLMAPI: One OpenAI-Compatible Endpoint for 34 Free LLM Providers</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Fri, 04 Sep 2026 09:01:45 +0000</pubDate>
      <link>https://dev.to/arshtechpro/freellmapi-one-openai-compatible-endpoint-for-34-free-llm-providers-3630</link>
      <guid>https://dev.to/arshtechpro/freellmapi-one-openai-compatible-endpoint-for-34-free-llm-providers-3630</guid>
      <description>&lt;p&gt;Almost every AI lab now hands out a free tier. Google, Groq, Cerebras, Mistral, Cohere, NVIDIA, Cloudflare, OpenRouter, and a couple dozen more. Each one on its own is small. A few million tokens a month, a few thousand requests a day. Stacked together, they turn into something you can actually prototype against.&lt;/p&gt;

&lt;p&gt;The problem is stacking them by hand. Thirty-four SDKs, thirty-four sets of rate limits, thirty-four places your request can fail at 2 AM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tashfeenahmed/freellmapi" rel="noopener noreferrer"&gt;FreeLLMAPI&lt;/a&gt; is an open-source router that collapses all of that into a single &lt;code&gt;/v1&lt;/code&gt; endpoint. You point any OpenAI client at your own machine, and it routes across whatever providers you've added keys for.&lt;/p&gt;




&lt;h2&gt;
  
  
  First, the question everyone asks: is it actually free?
&lt;/h2&gt;

&lt;p&gt;Short answer: yes, the software is free and stays free. There is a paid tier, but it does not gate the router.&lt;/p&gt;

&lt;p&gt;Here is the honest breakdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is free, permanently&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The router itself is MIT-licensed. Self-host it with Docker, npm, or the desktop app. No account with the project required to run it.&lt;/li&gt;
&lt;li&gt;Every feature works: routing, failover, rate tracking, the dashboard, analytics, the playground, all the API surfaces.&lt;/li&gt;
&lt;li&gt;The inference is free because &lt;em&gt;you&lt;/em&gt; bring your own free-tier provider keys. FreeLLMAPI does not resell tokens. It never sees your prompts on a remote server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What costs money&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One thing only: the &lt;strong&gt;live model catalog feed&lt;/strong&gt;. $19/year or $49 once for lifetime.&lt;/li&gt;
&lt;li&gt;Free installs get the same signed catalog, but from a monthly snapshot. A new model reaches free installs about 30 days after it hits the live feed. The project says free builds currently sit roughly 303 models behind.&lt;/li&gt;
&lt;li&gt;Nothing expires, nothing gets crippled, no request caps are added. Updates just arrive later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the mental model is: &lt;strong&gt;the software is free, the tokens are free (they're your own free tiers), and the $19/yr is a convenience subscription for same-day model catalog updates.&lt;/strong&gt; If you're fine being a month behind on newly-launched free models, you never pay anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch that isn't about money&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The repo is blunt about this, and so am I: this is for personal experimentation and learning. Not production. No frontier models, variable latency, no SLA, and the effective quality of the endpoint drops late in the day as the best free models hit their daily caps (they reset at UTC midnight). Your relationship with each upstream provider is still governed by the terms you agreed to when you signed up for them. Ship something real, swap in a paid API first.&lt;/p&gt;




&lt;h2&gt;
  
  
  So how does the "aggregator" actually work? Do I get an API key?
&lt;/h2&gt;

&lt;p&gt;Yes, but probably not the way you're imagining. There is no signup page where FreeLLMAPI hands you a key to a hosted service. It is local-first and single-user by design.&lt;/p&gt;

&lt;p&gt;The flow is two layers of keys:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: your provider keys (inbound).&lt;/strong&gt; You go and get free-tier API keys yourself from Google AI Studio, Groq, Cerebras, Mistral, and so on. You paste them into the FreeLLMAPI dashboard on the &lt;strong&gt;Keys&lt;/strong&gt; page. They get AES-256-GCM encrypted and stored in a local SQLite database, then decrypted in memory only for the duration of a request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: your unified key (outbound).&lt;/strong&gt; The router generates a single bearer token that looks like &lt;code&gt;freellmapi-...&lt;/code&gt;. That is the only credential your applications ever see. Your app never touches the provider keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your app  ──[freellmapi-xxx]──►  Local router  ──[real provider keys]──►  Groq
                                      │                                   Google
                                      │                                   Cerebras
                                      └─ picks, tracks limits, fails over  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What the router does per request:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Looks at your fallback chain and picks the highest-priority model that has a healthy key and is currently under all of its rate limits.&lt;/li&gt;
&lt;li&gt;Decrypts that provider key in memory and calls the provider.&lt;/li&gt;
&lt;li&gt;On a 429 or 5xx, it puts that key on cooldown and immediately retries the next model in your chain.&lt;/li&gt;
&lt;li&gt;Tracks RPM/RPD/TPM/TPD per &lt;code&gt;(provider, model, key)&lt;/code&gt; so it stays under every free-tier cap instead of discovering the cap by getting rejected.&lt;/li&gt;
&lt;li&gt;Returns an &lt;code&gt;X-Routed-Via: &amp;lt;provider&amp;gt;/&amp;lt;model&amp;gt;&lt;/code&gt; header so you can see who actually served the request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is also sticky sessions (a conversation stays on one model for 30 minutes so replies stay coherent), unified model entries when the same model exists on several providers, and named routing profiles you can switch per request with &lt;code&gt;auto:&amp;lt;profile&amp;gt;&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Simple steps to get running
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Install
&lt;/h3&gt;

&lt;p&gt;The one-liner needs Docker. It creates &lt;code&gt;~/freellmapi&lt;/code&gt;, generates an encryption key, pulls the image, and starts the container.&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://freellmapi.co/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If piping to bash makes you uncomfortable, the script is readable at the same URL first. Re-running it is safe: it keeps your existing &lt;code&gt;.env&lt;/code&gt; and encryption key.&lt;/p&gt;

&lt;p&gt;On Windows or macOS you can skip Docker entirely and grab the desktop installer from the GitHub Releases page. It runs the whole router and dashboard from your tray, and there is no password to set up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Open the dashboard
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Add your free provider keys
&lt;/h3&gt;

&lt;p&gt;Go to the &lt;strong&gt;Keys&lt;/strong&gt; page and paste in whatever free-tier keys you have. Start with two or three, you don't need all thirty-four. Good ones to begin with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google AI Studio&lt;/strong&gt; for Gemini models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Groq&lt;/strong&gt; for very fast inference&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cerebras&lt;/strong&gt; for very fast inference&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mistral&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each key shows a status dot and when it was last health-checked, so you'll know immediately if you pasted a bad one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Set your fallback chain
&lt;/h3&gt;

&lt;p&gt;On the &lt;strong&gt;Models&lt;/strong&gt; page, drag your preferred models into order. That order is literally the routing priority. Top of the list gets tried first, and everything below it is your automatic failover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Copy your unified key
&lt;/h3&gt;

&lt;p&gt;It's in the header of the &lt;strong&gt;Keys&lt;/strong&gt; page, starting with &lt;code&gt;freellmapi-&lt;/code&gt;. This is the key your code uses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Point your code at it
&lt;/h3&gt;

&lt;p&gt;Nothing new to learn. It's the OpenAI SDK with a different &lt;code&gt;base_url&lt;/code&gt;.&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;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3001/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;freellmapi-your-unified-key&lt;/span&gt;&lt;span class="sh"&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;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# let the router choose
&lt;/span&gt;    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&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;role&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;user&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;content&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;Explain database indexes in two sentences.&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node is the same idea:&lt;br&gt;
&lt;/p&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="nx"&gt;OpenAI&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;openai&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;freellmapi-your-unified-key&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Explain database indexes in two sentences.&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;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And plain curl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:3001/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer freellmapi-your-unified-key"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model":"auto","messages":[{"role":"user","content":"hello"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;code&gt;model&lt;/code&gt; field you can pass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"auto"&lt;/code&gt; — router picks the best available&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"auto:fast"&lt;/code&gt; or &lt;code&gt;"auto:smart"&lt;/code&gt; — bias toward speed or capability&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"auto:&amp;lt;your-profile&amp;gt;"&lt;/code&gt; — a named chain you built in the dashboard&lt;/li&gt;
&lt;li&gt;an explicit model id — pin it to one model&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"fusion"&lt;/code&gt; — fan the prompt out to several free models in parallel and have a judge model synthesize one answer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 7 (optional): Wire up your coding agent
&lt;/h3&gt;

&lt;p&gt;This is where it gets genuinely useful. Most CLI agents configure themselves with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx freellmapi setup-claude &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:3001 &lt;span class="nt"&gt;--api-key&lt;/span&gt; &amp;lt;unified-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are generators for Codex CLI, Cline, Continue, Aider, OpenCode, Goose, Qwen Code, Roo, Kilo, Crush, DeepSeek Harness, and more. Every one supports &lt;code&gt;--dry-run&lt;/code&gt; and backs up your existing config before touching it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What surfaces you get
&lt;/h2&gt;

&lt;p&gt;Beyond &lt;code&gt;/v1/chat/completions&lt;/code&gt;, the router implements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/v1/responses&lt;/code&gt; (what Codex CLI needs), &lt;code&gt;/v1/completions&lt;/code&gt; for editor ghost-text&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1/embeddings&lt;/code&gt;, &lt;code&gt;/v1/models&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1/images/generations&lt;/code&gt;, &lt;code&gt;/v1/videos/generations&lt;/code&gt;, &lt;code&gt;/v1/audio/speech&lt;/code&gt;, &lt;code&gt;/v1/audio/transcriptions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1/messages&lt;/code&gt; — Anthropic's wire format, so Claude Code and the Anthropic SDKs work against your free pool&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/v1beta&lt;/code&gt; — Gemini's native surface for Gemini CLI&lt;/li&gt;
&lt;li&gt;Optional Ollama emulation for Zed and JetBrains AI&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/mcp&lt;/code&gt; — an MCP server so agents can introspect available models and provider health mid-session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tool calling and structured outputs round-trip across providers, including a nice touch where plain-text tool calls from weaker models get rescued into proper &lt;code&gt;tool_calls&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also add a &lt;strong&gt;custom&lt;/strong&gt; provider pointing at any OpenAI-compatible endpoint: llama.cpp, LM Studio, vLLM, a local Ollama, or a remote gateway. So your local models sit in the same fallback chain as the cloud free tiers.&lt;/p&gt;




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

&lt;p&gt;Use it if you are: prototyping, building side projects, running a coding agent on your own machine, learning how routing and failover work, or just tired of managing eleven different &lt;code&gt;.env&lt;/code&gt; variables.&lt;/p&gt;

&lt;p&gt;Do not use it if you are: shipping to customers, need an SLA, need frontier-model quality, or need predictable latency.&lt;/p&gt;

&lt;p&gt;It runs on anything with Node 20+, including a Raspberry Pi, at around 40 MB RSS idle.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/tashfeenahmed/freellmapi" rel="noopener noreferrer"&gt;github.com/tashfeenahmed/freellmapi&lt;/a&gt;&lt;/p&gt;




</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>llm</category>
    </item>
    <item>
      <title>Humanizer: The 40k-Star Agent Skill That Strips AI Tells From Your Writing</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 03 Sep 2026 10:43:45 +0000</pubDate>
      <link>https://dev.to/arshtechpro/humanizer-the-40k-star-agent-skill-that-strips-ai-tells-from-your-writing-4758</link>
      <guid>https://dev.to/arshtechpro/humanizer-the-40k-star-agent-skill-that-strips-ai-tells-from-your-writing-4758</guid>
      <description>&lt;p&gt;Wikipedia editors have a problem. People keep dumping LLM output into articles, and it reads badly in a specific, recognizable way. So WikiProject AI Cleanup wrote up a page cataloguing the tells: the inflated importance, the forced triads, the "not just X, it's Y" construction, the paragraph that ends by assuring you the future looks bright.&lt;/p&gt;

&lt;p&gt;Siqi Chen looked at that page and had an idea that is obvious in retrospect. If someone has already collated a detailed list of how AI writing gives itself away, you can hand that list to an LLM and tell it not to do any of it. He asked Claude Code to read the article and build a skill from it.&lt;/p&gt;

&lt;p&gt;The result is &lt;a href="https://github.com/blader/humanizer" rel="noopener noreferrer"&gt;blader/humanizer&lt;/a&gt;, now sitting at roughly 40k stars.&lt;/p&gt;

&lt;h2&gt;
  
  
  It is a Markdown file
&lt;/h2&gt;

&lt;p&gt;This is the part that surprises people. Humanizer is a &lt;code&gt;SKILL.md&lt;/code&gt; file. There is no package, no model, no API, no dependency tree. It is instructions.&lt;/p&gt;

&lt;p&gt;That sounds like a limitation and is actually the reason it spread. Because it is plain Markdown following the Agent Skills format, it runs on anything that supports skills. And if your tool does not support skills, you can open the file and paste it into a system prompt. Distribution problem solved by not having one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Humanizer encodes 35 patterns drawn from Wikipedia's "Signs of AI writing" page. Each one is a named failure mode with a before and after example, which matters more than it sounds: the model is not being told "write naturally," which is useless advice. It is being told "you wrote 'serves as a testament to' and here is the specific replacement."&lt;/p&gt;

&lt;p&gt;The run is two passes. It rewrites first, without treating the original paragraph structure as fixed. Then it checks that draft against the 35 patterns and against the original claims, and rewrites whatever is still wrong. When you paste text in, it shows you both stages plus a short critique of what still sounds artificial, which is genuinely useful for learning your own tells.&lt;/p&gt;

&lt;p&gt;The patterns fall into five groups:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content.&lt;/strong&gt; Inflated importance, name-dropping, vague attribution ("experts believe"), the formulaic "despite challenges, it continues to thrive" arc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language and grammar.&lt;/strong&gt; Overused AI vocabulary (testament, landscape, showcasing, delve-adjacent stuff), avoiding plain "is" and "has" in favor of "serves as" and "boasts," the not-X-but-Y construction, forced groups of three, fake "from X to Y" ranges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Style.&lt;/strong&gt; Em dashes, excessive bold, lists where prose would do, title case headings, emojis, curly quotes, hyphen pileups like "cross-functional, data-driven, client-facing," manufactured profundity ("at its core, what matters is"), and fake-candid openings ("Honestly? It depends").&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chatbot residue.&lt;/strong&gt; "I hope this helps," knowledge-cutoff disclaimers, "Great question!"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filler.&lt;/strong&gt; "In order to" instead of "to." Stacked hedges like "could potentially possibly." Endings that gesture vaguely at a bright future.&lt;/p&gt;

&lt;p&gt;A quick illustration of the shape of the fix:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; The migration serves as a testament to our team's commitment to scalability, reliability, and performance — proving that with the right architecture, the future looks bright.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt; The migration cut p99 latency from 1.2s to 340ms. We still have two services on the old queue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Same topic. One sentence says nothing and one says something.&lt;/p&gt;

&lt;p&gt;Two design decisions deserve credit. First, there is a hard no-fabrication rule, added in v2.9.0. Names, numbers, dates, quotes, and citations have to come from the source or from you. If a detail is missing, it is supposed to ask rather than invent one, which is exactly the failure mode you would expect from a tool whose job is to make text sound more lived-in and specific. Second, if you paste in two or three paragraphs of your own writing as a sample, it follows your rhythm and quirks instead of its default style rules. That is the difference between "sounds human" and "sounds like you."&lt;/p&gt;

&lt;p&gt;Pointed at a file, it only touches prose. Code blocks, data, frontmatter, and link targets stay put.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it work with Claude?
&lt;/h2&gt;

&lt;p&gt;Yes, three different ways, and the repo has clearly been maintained with Claude in mind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;, via the skills CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add blader/humanizer &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop &lt;code&gt;--global&lt;/code&gt; to install into the current project only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code as a plugin&lt;/strong&gt; (2.1.142 or newer):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add blader/humanizer
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;humanizer@humanizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invoke it with &lt;code&gt;/humanizer:humanizer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Desktop&lt;/strong&gt;: download the repo as a ZIP and upload it as a skill. This one was broken for a while. The repo used a symlink for the plugin path, and Claude Desktop could not handle it in the source archive. It was fixed twice, first with a dedicated release asset in v2.11.1, then properly in v2.11.2 by dropping the symlink entirely once Claude Code began loading the root &lt;code&gt;SKILL.md&lt;/code&gt; directly. If you tried this months ago and it failed, try again.&lt;/p&gt;

&lt;p&gt;Once installed, either invocation style works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/humanizer

[paste your text here]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or just ask for it in plain language, including pointing at a path: "Humanize the prose in docs/launch-post.md."&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it work with other agents?
&lt;/h2&gt;

&lt;p&gt;Also yes, and this is where the "it's just Markdown" decision pays off. The &lt;code&gt;npx skills&lt;/code&gt; CLI targets 40-plus agents, and Humanizer is a normal skill package, so it installs to any of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add blader/humanizer &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; codex
npx skills add blader/humanizer &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; cursor &lt;span class="nt"&gt;--agent&lt;/span&gt; opencode
npx skills add blader/humanizer &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Common targets and where the files land:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;--agent&lt;/code&gt; flag&lt;/th&gt;
&lt;th&gt;Global path&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude-code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.claude/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;&lt;code&gt;codex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.codex/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cursor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.cursor/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini CLI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemini-cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.gemini/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;&lt;code&gt;github-copilot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.copilot/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenCode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;opencode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.opencode/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amp&lt;/td&gt;
&lt;td&gt;&lt;code&gt;amp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.config/agents/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cline&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cline&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.cline/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windsurf&lt;/td&gt;
&lt;td&gt;&lt;code&gt;windsurf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.windsurf/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Kiro, Qwen Code, Roo, Trae, Goose, Continue, and others are supported too. Remember to reload skills in the target agent afterward.&lt;/p&gt;

&lt;p&gt;For anything not on that list, the manual path always works: copy &lt;code&gt;SKILL.md&lt;/code&gt; into the agent's skill folder. And for a plain chat interface with no skill support at all, open &lt;code&gt;SKILL.md&lt;/code&gt;, copy the contents, and paste it as your system prompt or as the preamble to your request. You lose the slash command and the file-editing mode. The 35 patterns still apply.&lt;/p&gt;

&lt;p&gt;The honest caveat on cross-agent use: the skill is a prompt, so results depend on how well the underlying model follows a long instruction set. A frontier model with good instruction-following will apply all 35 patterns and self-critique properly. A smaller local model may catch the obvious vocabulary swaps and quietly skip the harder judgment calls. Same file, different mileage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It is not an AI-detector defeat button.&lt;/strong&gt; People reach for it that way and the framing is wrong in both directions. Detectors are unreliable enough that they flag human writing regularly, so "passing" one proves little. And Humanizer's actual job is removing bad writing habits, not adversarially targeting a classifier. If you are trying to sneak past an academic integrity check, this is the wrong tool and a bad plan. If you are trying to make a launch post not read like a launch post, it is the right tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some patterns are opinions, not rules.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It cannot add substance.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overcorrection is real.&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Worth using?
&lt;/h2&gt;

&lt;p&gt;For a Markdown file with an MIT license, the cost of trying it is close to zero, and it is the rare tool where reading the source teaches you something even if you never install it. The 35 patterns are a decent editing checklist on their own.&lt;/p&gt;

&lt;p&gt;The realistic workflow is not "generate with AI, run Humanizer, ship." It is: write the draft, make sure it contains real specifics only you have, then run Humanizer to strip the stylistic residue, then read the output yourself. It is a de-slopping pass, not a ghostwriter.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/blader/humanizer" rel="noopener noreferrer"&gt;github.com/blader/humanizer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agentskills</category>
      <category>productivity</category>
      <category>agents</category>
    </item>
    <item>
      <title>TimesFM: Google's Foundation Model for Time Series, Explained for Developers</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Thu, 03 Sep 2026 10:21:07 +0000</pubDate>
      <link>https://dev.to/arshtechpro/timesfm-googles-foundation-model-for-time-series-explained-for-developers-3jf9</link>
      <guid>https://dev.to/arshtechpro/timesfm-googles-foundation-model-for-time-series-explained-for-developers-3jf9</guid>
      <description>&lt;p&gt;TimesFM proposes a different deal: skip the training step entirely.&lt;/p&gt;

&lt;p&gt;It is a pretrained model from Google Research that forecasts time series it has never seen before. Same idea as an LLM, except instead of predicting the next word, it predicts the next value. You hand it a NumPy array of history, tell it how far ahead to look, and get a forecast back. No training loop, no hyperparameter search.&lt;/p&gt;

&lt;p&gt;This post covers what it actually does, how the API feels, what landed in the brand-new 3.0 release.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mental model: patches are tokens
&lt;/h2&gt;

&lt;p&gt;An LLM chops text into tokens and learns to predict the next one. TimesFM chops a time series into &lt;strong&gt;patches&lt;/strong&gt; (contiguous windows of 32 time steps) and learns to predict the next patch.&lt;/p&gt;

&lt;p&gt;That is basically the whole idea. A decoder-only transformer, the same family as GPT, pointed at numbers instead of text.&lt;/p&gt;

&lt;p&gt;Patching matters for two practical reasons. Attention cost grows with sequence length, so grouping 32 points into one token keeps long histories affordable. And a patch captures a local shape (a weekly cycle, a spike, a slow drift) as a single unit, which is closer to how time series actually behave than treating each individual point as a token.&lt;/p&gt;

&lt;p&gt;The training data is the other half of the story. TimesFM was pretrained on a corpus of over a trillion time points spanning retail, finance, web traffic, energy, and synthetic data. It has seen enough patterns of "sales-shaped thing" and "traffic-shaped thing" that when you hand it yours, it recognizes the family. That is what makes zero-shot forecasting work.&lt;/p&gt;

&lt;p&gt;You also get uncertainty for free. The model outputs 9 quantiles (10th through 90th percentile) at every step, not just a single line. If you have ever had to bolt confidence intervals onto a forecast after the fact, this is a real convenience.&lt;/p&gt;




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

&lt;p&gt;Installation is a one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;timesfm[torch]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from source with &lt;code&gt;uv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/google-research/timesfm.git
&lt;span class="nb"&gt;cd &lt;/span&gt;timesfm
uv 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
uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; .[torch]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The 2.5 API
&lt;/h3&gt;

&lt;p&gt;This is the API most tutorials and existing code use. You load a checkpoint, compile it once with a config, then call &lt;code&gt;forecast()&lt;/code&gt;:&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;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timesfm&lt;/span&gt;

&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_float32_matmul_precision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;timesfm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimesFM_2p5_200M_torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google/timesfm-2.5-200m-pytorch&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;timesfm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ForecastConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;max_context&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="n"&gt;max_horizon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;normalize_inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;use_continuous_quantile_head&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;force_flip_invariance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;infer_is_positive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fix_quantile_crossing&lt;/span&gt;&lt;span class="o"&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="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;point_forecast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantile_forecast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forecast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;horizon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;linspace&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="mi"&gt;1&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;linspace&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="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;67&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;point_forecast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;     &lt;span class="c1"&gt;# (2, 12)
&lt;/span&gt;&lt;span class="n"&gt;quantile_forecast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;  &lt;span class="c1"&gt;# (2, 12, 10)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things worth noticing. The inputs are plain 1D arrays and they do &lt;strong&gt;not&lt;/strong&gt; have to be the same length, which is genuinely nice when you are forecasting a batch of products with different histories. And a few config flags do real work: &lt;code&gt;infer_is_positive&lt;/code&gt; stops the model predicting negative sales, &lt;code&gt;fix_quantile_crossing&lt;/code&gt; prevents the 60th percentile landing below the 40th.&lt;/p&gt;

&lt;p&gt;Swapping in your own data is the boring part, which is the point:&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;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weekly_demand.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_dates&lt;/span&gt;&lt;span class="o"&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;week&lt;/span&gt;&lt;span class="sh"&gt;"&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;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;demand&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forecast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;horizon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a 52-week forecast with prediction intervals, from a CSV, with no training.&lt;/p&gt;




&lt;h2&gt;
  
  
  What changed in 3.0
&lt;/h2&gt;

&lt;p&gt;TimesFM 3.0 landed in late August 2026, and it is a bigger jump than the version number suggests.&lt;/p&gt;

&lt;p&gt;Every checkpoint through 2.5 was strictly &lt;strong&gt;univariate&lt;/strong&gt;. One series, its own history, nothing else. That is a real limitation, because most forecasting problems in the wild are not like that. If you are forecasting ice cream sales, past sales alone miss the picture: related product sales matter, foot traffic matters, and crucially, the promotion you already scheduled for next Tuesday matters.&lt;/p&gt;

&lt;p&gt;3.0 is natively multivariate. It brings three things that were previously awkward or impossible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple targets.&lt;/strong&gt; Forecast several related series jointly and let the model use the correlations between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Past covariates.&lt;/strong&gt; Features you only know historically, like last month's foot traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Past-future covariates.&lt;/strong&gt; Features you know in advance, like scheduled promotions, holidays, or a weather forecast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the interesting capability. The model learns the promotion-to-sales relationship from your historical context, then applies it to future days where you have a promotion planned. A univariate model just projects the weekly pattern forward and misses the bump entirely.&lt;/p&gt;

&lt;p&gt;Architecturally, 3.0 does this with alternating attention. Tokens attend &lt;strong&gt;horizontally&lt;/strong&gt; across time (strictly causal, so no leakage from the future), then &lt;strong&gt;vertically&lt;/strong&gt; across series at each time step, so the model can learn how a spike in one series relates to another. Those two layers alternate through the stack.&lt;/p&gt;

&lt;p&gt;It also stopped decoding autoregressively. Earlier versions generated one patch at a time, which meant latency and compounding errors over long horizons. 3.0 appends masked placeholder tokens for the whole future window and fills them all in a single forward pass.&lt;/p&gt;

&lt;p&gt;The 3.0 API is different from 2.5, so this is not a drop-in upgrade:&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;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;timesfm3&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TimesFM3Evaluator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ModelConfig&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ModelConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;checkpoint_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google/timesfm-3.0-pytorch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;per_core_batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&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;forecaster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimesFM3Evaluator&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="n"&gt;context_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;horizon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;

&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randn&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="n"&gt;context_len&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;past_only_cov&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randn&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="n"&gt;context_len&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;past_future_cov&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randn&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="n"&gt;context_len&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;horizon&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;forecaster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict_batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;contexts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;horizon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;horizon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;past_only_covariates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;past_only_cov&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;past_future_covariates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;past_future_cov&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;return_quantiles&lt;/span&gt;&lt;span class="o"&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="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;outputs&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="n"&gt;forecast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;    &lt;span class="c1"&gt;# (3, 24)
&lt;/span&gt;&lt;span class="n"&gt;outputs&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="n"&gt;quantiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;   &lt;span class="c1"&gt;# (3, 24, 9)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the shape of &lt;code&gt;past_future_cov&lt;/code&gt;: it spans context &lt;strong&gt;plus&lt;/strong&gt; horizon, because you are telling the model about events that have not happened yet.&lt;/p&gt;

&lt;p&gt;On benchmarks, Google reports 3.0 taking the top average rank among pretrained foundation models on GIFT-Eval, fev-bench, and the TIME leaderboard, on both point and probabilistic metrics, against competitors including Chronos-2 and the Toto 2.0 family. Notably, it wins even in univariate mode, before you give it any covariates at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  The catch nobody mentions in the benchmark charts
&lt;/h2&gt;

&lt;p&gt;Read this part before you plan a sprint around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 3.0 weights are not open for commercial use.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The source code in the repo is Apache-2.0, and model weights &lt;strong&gt;up to 2.5&lt;/strong&gt; are Apache-2.0. But the 3.0 pretrained weights ship under a separate &lt;code&gt;timesfm-non-commercial-license-v1.0&lt;/code&gt;, restricted to non-commercial, non-production use. Commercial or production use of the default 3.0 weights is not permitted.&lt;/p&gt;

&lt;p&gt;So the practical situation right now is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;TimesFM 2.5&lt;/th&gt;
&lt;th&gt;TimesFM 3.0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parameters&lt;/td&gt;
&lt;td&gt;200M&lt;/td&gt;
&lt;td&gt;330M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context length&lt;/td&gt;
&lt;td&gt;up to 16k&lt;/td&gt;
&lt;td&gt;patch-based, 32-step patches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multivariate&lt;/td&gt;
&lt;td&gt;No (XReg covariates bolted on)&lt;/td&gt;
&lt;td&gt;Yes, native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Future-known covariates&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td&gt;Autoregressive per patch&lt;/td&gt;
&lt;td&gt;Single forward pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weights license&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;Non-commercial only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The best model is the one you probably cannot ship. The one you can ship is a version behind. That may change, and Google has said BigQuery integration for 3.0 is coming, but plan against what is true today.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Yes, if any of these describe you:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have a lot of series and no time to model each one. This is the killer use case. Tuning ARIMA for one series is fine; doing it for 5,000 SKUs is not a job anyone wants. Zero-shot inference across a batch is a single call.&lt;/p&gt;

&lt;p&gt;You need a baseline yesterday. Even if you eventually build something bespoke, having a credible forecast in twenty minutes tells you whether the problem is hard and what score you need to beat.&lt;/p&gt;

&lt;p&gt;You want uncertainty without extra work. Quantiles come out of the box.&lt;/p&gt;

&lt;p&gt;You are already on Google Cloud. TimesFM is wired into BigQuery ML behind an &lt;code&gt;AI.FORECAST&lt;/code&gt; SQL call, into Connected Sheets, and into Vertex Model Garden. If your data already lives in BigQuery, forecasting becomes a query rather than a project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be skeptical if:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have one series and years of clean history. A well-tuned domain model with your actual business logic baked in will often beat a general-purpose one. Foundation models win on breadth, not on any single well-understood problem.&lt;/p&gt;

&lt;p&gt;Your data is genuinely weird. Sparse intermittent demand, hard structural breaks, series driven mostly by exogenous shocks the model cannot see. Zero-shot means the model brings priors from other people's data, and sometimes those priors are simply wrong for you.&lt;/p&gt;

&lt;p&gt;You need commercial deployment of the newest model. See the license section above.&lt;/p&gt;

&lt;p&gt;You need CPU-cheap inference at scale. It is a 200M to 330M parameter transformer. That is small next to an LLM but not free, and the examples assume a GPU.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Repo and examples: &lt;a href="https://github.com/google-research/timesfm" rel="noopener noreferrer"&gt;github.com/google-research/timesfm&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One note: this is a research release, not an officially supported Google product. Treat it accordingly in anything load-bearing.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>ai</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Omarchy: an opinionated Arch install that ships someone else's taste</title>
      <dc:creator>ArshTechPro</dc:creator>
      <pubDate>Fri, 28 Aug 2026 11:14:53 +0000</pubDate>
      <link>https://dev.to/arshtechpro/omarchy-an-opinionated-arch-install-that-ships-someone-elses-taste-2p3g</link>
      <guid>https://dev.to/arshtechpro/omarchy-an-opinionated-arch-install-that-ships-someone-elses-taste-2p3g</guid>
      <description>&lt;p&gt;Most Linux distributions hand you a foundation and a shrug. Omarchy hands you a finished desk.&lt;/p&gt;

&lt;p&gt;It is an omakase Linux distribution based on Arch, the tiling window manager Hyprland, and the desktop construction-kit Quickshell. "Omakase" is the sushi term: you don't order, the chef decides. In this case the chef is DHH, and the distribution is the answer to a specific question — what if someone spent a year making all the tiling-WM decisions for you, and you just used the result?&lt;/p&gt;

&lt;p&gt;The project is &lt;a href="https://github.com/basecamp/omarchy" rel="noopener noreferrer"&gt;MIT licensed&lt;/a&gt;, incubated at 37signals, and is now on version 4.x.&lt;/p&gt;

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

&lt;p&gt;Strip the branding and Omarchy is three things stacked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An installer.&lt;/strong&gt; An ISO that provisions Arch with full-disk encryption, sane partitioning, and a working graphical session in a few minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A configuration layer.&lt;/strong&gt; Hyprland, Quickshell, a top bar, a theming system, a unified keybinding scheme, and dotfiles for tmux, Neovim, and your shell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A curated software set.&lt;/strong&gt; Neovim, Chromium, Obsidian, LibreOffice, Kdenlive, OBS Studio, and more.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The repo itself is 82% shell, 8% Lua, sitting at around 4,300 commits. That composition tells you the honest truth about the project: it is a very well-maintained pile of install scripts and config files, not a novel operating system. That is not a criticism. It's the reason you can read it, fork it, and steal from it.&lt;/p&gt;

&lt;p&gt;The framing in the manual is explicit about what it's optimizing for: a beautiful system is a motivating system, and productivity has always been downstream from motivation. Whether you buy that argument will largely determine whether this distribution is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You download the ISO, write it to a USB stick, boot off it, and answer a few configuration questions. It can be done in under a minute on the fastest modern machines, but it shouldn't take more than 5 minutes even on an older computer.&lt;/p&gt;

&lt;p&gt;Three things to know before you start:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure Boot has to go.&lt;/strong&gt; You must turn off Secure Boot and/or TPM in the BIOS to be able to install Omarchy. If your machine is corporate-managed or you dual-boot Windows with BitLocker on, plan for that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encryption is the default and it changes your keyboard requirements.&lt;/strong&gt; The installation defaults to full encryption, and the full-disk encryption won't allow you to enter the password from a Bluetooth keyboard at startup. You need a wired or 2.4GHz keyboard for the boot prompt. You can hit Ctrl + C on the disk formatting confirmation to switch to an encryption-less installation if you're building a throwaway box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can dual boot.&lt;/strong&gt; You can choose between a full-disk install, which takes over the entire drive, or a free-space install, which puts Omarchy in the unallocated space on a drive. The full-disk option will wipe the selected drive, so back up first.&lt;/p&gt;

&lt;p&gt;Two installer details I didn't expect and think are genuinely well designed:&lt;/p&gt;

&lt;p&gt;If you're setting up a machine for someone else, hit Ctrl + C on the very first screen and Omarchy will prepare the machine for another owner instead. The system installs right away, but keyboard layout, username, and password are deferred until first boot, and the password the new owner picks becomes the encryption password.&lt;/p&gt;

&lt;p&gt;The ISO can also install completely on its own — no keyboard, no wizard — when it's handed its configuration on a second drive, which is how you treat Omarchy as a base image for VMs and fleet machines.&lt;/p&gt;

&lt;p&gt;That second one is the part most reviews skip, and it's the one that makes this interesting beyond a personal laptop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The keyboard-first part
&lt;/h2&gt;

&lt;p&gt;Omarchy is a tiling window manager setup, so almost everything is a binding. &lt;code&gt;Super + K&lt;/code&gt; shows you all of them, which is the only hotkey you actually need to memorize on day one.&lt;/p&gt;

&lt;p&gt;A representative slice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hotkey&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Space&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Omarchy menu (apps and everything else)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Return&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Shift + Return&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Shift + N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Neovim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Arrow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move focus in that direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Shift + Arrow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swap window in that direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + 1/2/3/4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Jump to workspace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle tiling/floating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Super + Ctrl + Shift + Space&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pick a new theme&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The one I want to call out separately is the clipboard. On most Linux desktops you need &lt;code&gt;Ctrl + Shift + C/V&lt;/code&gt; in the terminal and &lt;code&gt;Ctrl + C/V&lt;/code&gt; everywhere else. Omarchy binds &lt;code&gt;Super + C&lt;/code&gt;, &lt;code&gt;Super + X&lt;/code&gt;, and &lt;code&gt;Super + V&lt;/code&gt; and they work in both places. It is a small thing that removes a daily papercut, and it is a good example of what "opinionated" buys you: someone noticed the inconsistency and just fixed it globally.&lt;/p&gt;

&lt;p&gt;Bindings live in &lt;code&gt;~/.config/hypr/bindings.lua&lt;/code&gt;. Lua config rather than a bespoke DSL, which means real conditionals and loops if you want them.&lt;/p&gt;

&lt;p&gt;There is also a tmux layer with its own binding set (&lt;code&gt;Super + Alt + K&lt;/code&gt; to view), including layout helpers like &lt;code&gt;tdl &amp;lt;ai&amp;gt;&lt;/code&gt; to spin up an editor + AI + terminal pane arrangement in one command.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI-workstation angle
&lt;/h2&gt;

&lt;p&gt;This is where Omarchy 4 diverges from being "a nice Hyprland config." A few of the defaults are built around agentic coding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Super + Ctrl + Return&lt;/code&gt; opens Herdr, an agent manager, with its own binding set under &lt;code&gt;Super + Ctrl + K&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Super + Shift + Ctrl + A&lt;/code&gt; opens an agent picker&lt;/li&gt;
&lt;li&gt;The tmux layout functions take an AI argument as a first-class parameter&lt;/li&gt;
&lt;li&gt;Dictation is a first-class install option, with push-to-talk on &lt;code&gt;F9&lt;/code&gt; and toggle on &lt;code&gt;Super + Ctrl + X&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Super + Ctrl + Print Screen&lt;/code&gt; does OCR text extraction from anything on screen straight to the clipboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run coding agents in terminals all day, the shape of this system was designed by someone doing the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The maintenance question
&lt;/h2&gt;

&lt;p&gt;The usual worry with a one-person opinionated distribution is what happens when that person moves on. Omarchy just answered it with money: the Omacom Foundation was incorporated as a nonprofit to hold the trademarks, fund the infrastructure, promote the work, and support the open-source projects and developers Omarchy depends on. Eight founding patrons contributed $1 million each, including Tobi Lütke, Patrick Collison, Michael Dell, Jack Dorsey, Matthew Prince, Brendan Iribe, and Jason Fried, with a further $2 million added from Drew Houston and Peter Steinberger.&lt;/p&gt;

&lt;p&gt;Ten million dollars does not guarantee good software. What it does buy is runway, infrastructure, and a reason to believe the ISO will still be built in three years. For a distribution you'd put on a work machine, that matters more than any feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I'd push back
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It is Arch underneath, with everything that implies.&lt;/strong&gt; Rolling release, no LTS, and when something breaks mid-week you are debugging Arch. Omarchy ships system snapshots to soften this, but the failure modes are Arch's failure modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure Boot off is a real cost for some people.&lt;/strong&gt; If your employer requires it, or you want measured boot as part of your threat model, this is a non-starter and no amount of theming fixes it.&lt;/p&gt;

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

&lt;p&gt;It depends almost entirely on which of these you are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it if&lt;/strong&gt; you already want to live in a terminal and a tiling WM, and the thing stopping you is the two weekends of config work. That is precisely the cost Omarchy eliminates. You get someone's finished, coherent, actively maintained setup instead of your own half-finished one, and you can read the shell scripts to understand every decision it made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it if&lt;/strong&gt; you want a reproducible dev machine image. The unattended install path is the most underrated feature here. A pinned ISO plus a config drive gets you identical, encrypted, fully-provisioned workstations across a team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skip it if&lt;/strong&gt; you need Secure Boot, need an LTS release cadence, or do work that is fundamentally mouse-driven and GUI-heavy. Skip it if you enjoy building your own environment, because Omarchy's entire value proposition is taking that job away from you.&lt;/p&gt;




&lt;p&gt;Repo: &lt;a href="https://github.com/basecamp/omarchy" rel="noopener noreferrer"&gt;github.com/basecamp/omarchy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
