<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Tuist's blog</title>
  <subtitle>Blog posts by the Tuist team.</subtitle>
  <link href="https://tuist.dev/blog"/>
  <link href="https://tuist.dev/blog/atom.xml" rel="self"/>
  <id>https://tuist.dev/blog</id>
  <updated>Sat, 28 Jul 2018 00:00:00 +0000</updated>

  
    <entry>
      <title><![CDATA[ The Three Layers of Developer Productivity ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Most companies optimize developer productivity by throwing faster machines at the problem. But productivity has three layers, and ignoring the hard ones means wasting the easy ones. ]]></summary>
      <link href="https://tuist.dev/blog/2026/03/04/three-layers-of-developer-productivity"/>
      <id>https://tuist.dev/blog/2026/03/04/three-layers-of-developer-productivity</id>
      <updated>Wed, 04 Mar 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When an organization grows past a certain size, someone eventually says the words out loud: &quot;We need a platform team.&quot; It happens when builds start taking too long, when flaky tests erode trust, when onboarding a new engineer takes a week instead of a day. The toolchain that once felt invisible starts becoming the loudest thing in the room.</p>
<p>
I joined one of those teams at <a href="https://www.shopify.com">Shopify</a>. It was called Mobile Tooling, part of a broader group called Dev Acceleration. The premise was simple: if you have hundreds of engineers using build systems, test runners, and deployment pipelines every day, you need a team that ensures those tools are used in the most optimal way possible. Human capital is expensive. You do not want engineers sitting idle waiting for a build to finish. You do not want them rerunning a test suite because they cannot trust the results. You want every resource, human and machine, working at its best.</p>
<p>
The reason these teams exist comes down to two things.</p>
<p>
First, understanding developer tooling at a deep level is rare. You need years of experience with build systems, test runners, and the kinds of failures that only emerge at scale. Knowing how a compilation graph distributes work across cores, understanding why a particular dependency ordering creates bottlenecks, recognizing when a configuration choice made two years ago is now costing you minutes on every build. <strong>This is not knowledge you pick up in a weekend.</strong> And asking a product engineer to context-switch into this work is a big stretch. It is like asking a chef to also be the plumber. They could probably figure it out, but you are wasting their best skills.</p>
<p>
Second, by the time you form a platform team, the codebase is already large and there is a lot of activity happening. Making meaningful improvements requires changes in configuration, changes in tool versions, reorganizing code. Doing all of that while business demands keep rolling in is incredibly difficult. It is surgery on a patient who refuses to stop running.</p>
<h2 id="the-reactive-trap" tabindex="-1" class="marketing__blog_post__body__content__heading">
The reactive trap<a href="#the-reactive-trap" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The reactive trap"></a></h2>
<p>
What happens in most organizations is that the platform team, if it exists at all, works reactively. Something breaks, someone complains, the team investigates. The tools themselves are not designed for observability. The interaction model is you and a terminal. You configure a build system once, you grow the codebase for months or years, and you rarely revisit that initial configuration. Performance degrades slowly, invisibly, like a frog in warming water.</p>
<p>
Think about it like a factory floor. Imagine a manufacturing plant where nobody monitors the machines. They were set up correctly on day one, and for a while everything runs smoothly. But over time, bearings wear down, belts loosen, calibrations drift. Because nobody is watching the telemetry, because there is no telemetry, the degradation accumulates silently. By the time someone notices that production has slowed by 30%, there is no single cause. It is a hundred small regressions stacked on top of each other, and untangling them is a nightmare.</p>
<p>
This is exactly what happens with developer tooling. And with coding agents entering the picture, the problem has accelerated. Agents produce code at a velocity that human developers never reached. If any step in the process of turning that code into a compiled artifact or running tests to validate it is slow or unreliable, you diminish the returns of the entire agentic workflow. Flaky tests that an agent cannot trust. Builds that take twenty minutes when they should take three. These are not minor annoyances anymore. <strong>They are bottlenecks that make expensive infrastructure less valuable.</strong></p>
<h2 id="three-layers" tabindex="-1" class="marketing__blog_post__body__content__heading">
Three layers<a href="#three-layers" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Three layers"></a></h2>
<p>
This is something we have been thinking about a lot at Tuist. Not just how to fix individual problems, but how to frame the entire space of developer productivity in a way that gives us and our users a shared mental model. Without a clear framework, it is easy to end up with a product that is a Frankenstein of features. A cache here, an analytics dashboard there, some CI integration over there. Everything loosely connected but lacking a coherent story. We needed a structure that would hold everything together and guide us as we expand into new ecosystems.</p>
<p>
What we arrived at is that developer productivity operates in three layers, stacked vertically. Each layer has its own characteristics, its own economics, and its own relationship to the others.</p>
<p>
Think of it like the human body. The toolchain is your form and technique: how efficiently you convert effort into movement. Compute is your muscles: raw strength and power. And cache is muscle memory: movements you have already learned that you do not need to think about again. A strong athlete with bad form wastes energy and gets injured. Perfect form still has a physical ceiling if the muscles are not there. And muscle memory is what lets you perform beyond what conscious effort alone allows, because you are not repeating work your body already knows how to do.</p>
<h3 id="the-toolchain-layer" tabindex="-1" class="marketing__blog_post__body__content__heading">
The toolchain layer<a href="#the-toolchain-layer" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The toolchain layer"></a></h3>
<p>
This is the layer closest to your project. It is the interaction between your code and the build systems, test runners, linters, and all the tools that turn source files into something that runs. It is the least glamorous layer and the one that gets the least investment. Not because it is the least important, but because it is the hardest.</p>
<p>
Going deep into the toolchain requires understanding every ecosystem individually. How Swift compilation graphs work is different from how Gradle resolves dependencies, which is different from how Vite bundles JavaScript. In networking, there is a concept called the narrow waist: the thin layer that sits between everything above and everything below, translating between the two. TCP/IP is the narrow waist of the internet. The toolchain layer is the narrow waist of developer productivity. It sits between your project and the infrastructure that builds it. But unlike TCP/IP, there is no universal protocol here. <strong>Every ecosystem has its own narrow waist</strong>, with its own data structures, its own performance characteristics, its own failure modes. You have to learn each one individually. There is no shortcut. This makes the toolchain layer unattractive for companies that need quick returns to meet investor expectations. You cannot raise a round, hire a team, and have ecosystem depth in six months. It does not work that way. We believe there is real value in making this investment, but it is value that compounds over years, not quarters. The trust you earn by going deep into an ecosystem, by contributing to the tools developers already use, by understanding problems at a level that most companies will not bother with, that trust is what turns into adoption and retention over time.</p>
<p>
The tools themselves are typically not designed for observability. Your build system speaks to you through standard output. You see a wall of text, maybe some timing information if you are lucky, and that is it. All the rich internal data, the compilation graph, the dependency ordering, the parallelization profile, is flattened into a log stream. You miss most of what is actually happening.</p>
<p>
And even when you can extract useful data, you need to understand it over time. Is a particular module a parallelization bottleneck? Maybe. But it depends on how often that module changes. If it changes on every commit, optimizing it is critical. If it changes once a quarter, it probably does not matter. Frequency is something you only know if you persist the data and analyze trends. <strong>A single snapshot tells you almost nothing.</strong></p>
<p>
This is the layer where we started at Tuist, and it is where we believe the most impactful work happens. We have gone deep into Xcode. We are going deep into Gradle. And as we expand into more ecosystems, we will do the same thing every time: understand the data structures the tools work with, observe them properly, and get to a point where we can proactively surface insights instead of waiting for someone to complain.</p>
<p>
Most companies avoid this layer because each ecosystem requires dedicated investment. They prefer solutions that look the same everywhere. That preference is understandable. <strong>It is also why the toolchain layer remains the most neglected.</strong></p>
<h3 id="the-compute-layer" tabindex="-1" class="marketing__blog_post__body__content__heading">
The compute layer<a href="#the-compute-layer" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The compute layer"></a></h3>
<p>
If the toolchain layer is your form, compute is your muscles. This is the raw power where the action happens. Your developer laptop. Your CI runner. And increasingly, the sandboxed environments where coding agents execute their work.</p>
<p>
Compute is where most of the money flows in our industry, because it is the easiest layer to invest in. It is tangible. You can measure it. You can compare specs. You can say &quot;my machine has 32 cores and 64 GB of RAM&quot; and feel like you have solved something. Companies compete on milliseconds of startup time, on core counts, on I/O throughput.</p>
<p>
And it matters. Of course it matters. A faster machine compiles code faster, runs tests faster, everything faster. But compute alone has a ceiling, and that ceiling is determined by physics. You can buy the most powerful machine available, and your build still takes however long it takes to process everything from scratch.</p>
<p>
Here is the part that I find genuinely fascinating: organizations pour money into faster compute while completely ignoring how their projects use that compute. If your compilation graph has one massive module that everything depends on, you will have one core working at full capacity while fifteen others sit idle waiting for it to finish. <strong>That is an expensive machine doing very little work.</strong> It is like a weightlifter with massive arms but terrible form. The strength is there, but most of it is wasted.</p>
<p>
The compute market is getting crowded. CI companies that have invested in their infrastructure for years are now offering those environments for agent workflows. Sandbox companies like <a href="https://www.daytona.io/">Daytona</a>, <a href="https://e2b.dev/">E2B</a>, and others are providing boxes for agents. Product companies like Linear, Codex, and others are spinning up their own environments. Everyone is offering compute because compute is a relatively straightforward product to build and sell.</p>
<p>
But when everyone is selling the same thing, differentiation becomes razor thin. Someone will always match your specs at a lower price. This is where companies that only do compute start to struggle. Their improvements become incremental: 200 milliseconds faster startup, 100 milliseconds less latency. Important, but diminishing.</p>
<h3 id="the-cache-layer" tabindex="-1" class="marketing__blog_post__body__content__heading">
The cache layer<a href="#the-cache-layer" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The cache layer"></a></h3>
<p>
At some point, no matter how fast your machine is, you hit the physical ceiling. Your cores are saturated. Your I/O is maxed. And yet you are compiling or testing something that someone else, maybe even you ten minutes ago, has already done. From the perspective of using resources optimally, repeating that work is waste.</p>
<p>
This is where caching enters. Build systems like <a href="https://bazel.build/remote/caching">Bazel</a> pioneered remote caching years ago. Gradle has it. Xcode introduced compilation caching recently. The trend is clear: caching is becoming a standard capability across ecosystems.</p>
<p>
The interesting tension with caching is that it introduces the network. You break through the physical ceiling of a single machine by distributing pre-computed results across a network. But in doing so, you make latency the new bottleneck. If you can pull a cached artifact in 5 milliseconds, caching is transformative. If it takes 500 milliseconds, you might be better off just rebuilding locally. <strong>The gains from caching are directly proportional to how close the cache is to the compute.</strong></p>
<p>
Going back to the body analogy: muscle memory only works if the recall is instant. If there is a delay between your brain sending the signal and your muscles executing the movement, you lose the advantage entirely. You might as well be learning the movement from scratch. Proximity between the memory and the muscles is everything.</p>
<p>
This is why compute and cache must be colocated. They are not independent layers you can optimize separately. They have to work together, physically close, with minimal latency between them. A fast machine with a distant cache is not much better than a fast machine with no cache at all.</p>
<p>
But low latency is only half the problem. The other half is access. A cache is only as useful as the number of contexts that can reach it. Today, your code builds in many places: your laptop, your CI runner, an agent sandbox, a colleague&#39;s machine. If the cache is only accessible from one of those contexts, you are still repeating work everywhere else.</p>
<p>
This is where many existing solutions fall short. GitHub Actions cache, for example, is tightly coupled to CI pipelines. It lives inside the CI compute and can only be accessed from within a workflow run. Your developers cannot pull from it locally. An agent running outside of GitHub Actions cannot benefit from it. The cache exists, but it is locked inside a single context. That is not a cache infrastructure. That is a feature of a CI product.</p>
<p>
<strong>A cache worth building needs to be accessible from anywhere the action happens.</strong> Multiple interfaces, multiple protocols, multiple entry points. Your build system should be able to reach it. Your IDE should be able to reach it. An agent running in a container somewhere should be able to reach it. The cache should be a piece of infrastructure that serves all compute, not a feature that serves one product.</p>
<h2 id="why-the-framework-matters" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why the framework matters<a href="#why-the-framework-matters" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why the framework matters"></a></h2>
<p>
The reason we wanted to capture these three layers as a mental model is that without it, we risk building a product that lacks coherence. When you expand into new build systems, when you ship new features, when you make architectural decisions, you need something to anchor those choices. Which layer does this feature serve? How does it interact with the other layers? Are we neglecting one in favor of another?</p>
<p>
Without this framework, you end up with a product that is a collection of loosely related tools. A cache that does not understand the toolchain. A compute layer that does not know about the cache. Analytics that show you numbers without telling you what to do about them. <strong>Each piece works in isolation but the whole is less than the sum of its parts.</strong></p>
<p>
With the framework, every decision has a place. When we jump into a new ecosystem like Gradle, we know exactly what we need to build: deep toolchain understanding, cache integration, and compute awareness. The same structure applies regardless of the technology. The specifics change, but the architecture does not.</p>
<h2 id="what-we-are-building" tabindex="-1" class="marketing__blog_post__body__content__heading">
What we are building<a href="#what-we-are-building" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What we are building"></a></h2>
<p>
At Tuist, we are designing the product so that you can choose the layer you need. You do not have to buy the whole stack. If you only want caching, you can deploy it close to your own compute and get the latency benefits without changing anything else. If you want compute and caching together, we will provide environments where they are colocated, so you do not have to think about proximity. It will just be fast.</p>
<p>
And then we layer the toolchain understanding on top. This is the part that ties everything together. We do not just give you a fast machine with a cache. We make sure you are using those things in the most optimal way possible. We look at your build graphs, your test runs, your compilation patterns, and we surface the things that are wasting your resources. Not as a dashboard you have to check. As proactive insights that tell you what to fix and why.</p>
<p>
This is the vision: we want to be the platform team that most organizations cannot afford to build themselves. Not a team of people you hire and retain and hope they stay long enough to accumulate the knowledge. A product that carries that knowledge, that watches your workflows, that understands your tools deeply enough to optimize them for you.</p>
<p>
We are making this accessible to everyone. Not just the companies with hundreds of engineers and the budget for a dedicated platform team. Everyone. The team of five that just started a project and wants to build good habits from the beginning. The solo developer who does not want to spend a weekend figuring out why their builds got slow.</p>
<p>
The three layers are simple enough to explain in a conversation. But they represent years of accumulated understanding of what actually matters for developer productivity. And they are the framework that will guide everything we build from here.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Velocity for Every Gradle Team ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We're bringing years of experience scaling Xcode projects to the Gradle ecosystem. Remote cache, build insights, test insights including flaky test detection are all available for your Gradle projects today. ]]></summary>
      <link href="https://tuist.dev/blog/2026/03/02/gradle"/>
      <id>https://tuist.dev/blog/2026/03/02/gradle</id>
      <updated>Mon, 02 Mar 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
We&#39;ve spent years helping teams scale their Xcode projects. Be it build caching, test insights, flaky test detection, or bundle analysis, we&#39;ve built these features because we&#39;ve seen firsthand how much time teams waste in slow builds, unreliable tests, and tooling gaps that no one has time to fill.</p>
<p>
Along the way, we noticed something. Many of the problems we were solving weren&#39;t unique to Xcode. Slow builds? Gradle has them too. Flaky tests blocking PRs? That&#39;s universal. Build cache infrastructure that&#39;s expensive and painful to maintain? Teams working with Gradle deal with this every day. The underlying challenges are remarkably similar across ecosystems.</p>
<p>
That&#39;s why we&#39;re excited to announce that Tuist now supports Gradle.</p>
<h2 id="what's-included" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s included<a href="#what's-included" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's included"></a></h2>
<h3 id="build-insights" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build insights<a href="#build-insights" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build insights"></a></h3>
<p>
Build time directly affects your feedback loop. As projects grow, build performance degrades. But most teams have no visibility into how or why. They track CI pipeline duration but can&#39;t answer basic questions: Which tasks take the longest? How does build time change across Gradle versions? Did that dependency upgrade actually make things worse? You can&#39;t improve what you can&#39;t measure. And with coding agents generating more changes than ever, slow builds don&#39;t just slow down one developer, they become a multiplier on wasted CI time across the whole team. </p>
<p>
The plugin automatically sends build analytics to Tuist, giving you visibility into task execution and cache behavior in the dashboard. You can track which tasks take the longest or how build performance evolves over time. No additional configuration is needed, build insights are collected automatically once the plugin is installed.</p>
<h3 id="remote-gradle-cache" tabindex="-1" class="marketing__blog_post__body__content__heading">
Remote Gradle cache<a href="#remote-gradle-cache" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Remote Gradle cache"></a></h3>
<p>
Once you understand where build time goes, caching is the most effective lever to reduce it. Tuist provides a <a href="https://docs.tuist.dev/en/guides/features/cache">remote cache</a> that integrates directly with <a href="https://docs.gradle.org/current/userguide/build_cache.html">Gradle&#39;s built-in build cache</a> to share build artifacts remotely. When a task&#39;s outputs are already cached, Gradle skips execution and pulls the result from Tuist&#39;s remote cache. Your team stops rebuilding the same things over and over, and CI times drop.</p>
<p>
But a remote cache is only as fast as the network between your builds and the storage. That&#39;s why Tuist hosts cache infrastructure with global coverage, giving you low latency no matter where your CI runners or developers are located. You get the speed of a local cache with the reach of a shared one, without provisioning or maintaining anything yourself.</p>
<p>
On top of that, you get full visibility into how the cache is performing, such as hit rate over time or individual cache keys for each Gradle task, so you can understand exactly what&#39;s being cached and why something missed.</p>
<p>
  <img src="/marketing/images/blog/2026/03/02/gradle/gradle-cache-insights.png" alt="Gradle cache insights showing hit rate, downloads, uploads, and per-build cache hit rates">
</p>
<h3 id="test-insights" tabindex="-1" class="marketing__blog_post__body__content__heading">
Test insights<a href="#test-insights" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Test insights"></a></h3>
<p>
A healthy test suite is a fast and reliable one. But as test suites grow, that&#39;s hard to maintain without data. Which tests are the slowest? Are they getting slower over time? Where should you focus your effort to get the biggest improvement? Without answers to these questions, test suite health degrades gradually until everyone just accepts that &quot;tests are slow.&quot;</p>
<p>
Tuist gives you the answers you need as the plugin automatically tracks every test run, individual test durations, failure patterns, and reliability trends. You can spot the slowest tests, catch regressions early, and focus your effort where it matters most.</p>
<h3 id="flaky-test-detection-and-quarantine" tabindex="-1" class="marketing__blog_post__body__content__heading">
Flaky test detection and quarantine<a href="#flaky-test-detection-and-quarantine" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Flaky test detection and quarantine"></a></h3>
<p>
You change one line of code, push, wait for CI, and it fails on a completely unrelated test. You retry. Someone else merges in the meantime, so now you have conflicts. By the time you&#39;re green and merged, an hour and a half has passed — for a one-line change. Every retry is a context switch, every false failure is a distraction from real work, and most teams have no idea how much time they&#39;re losing. Worse, developers stop trusting the test suite. &quot;It&#39;s probably just that flaky test&quot; becomes the default assumption, and real bugs slip through.</p>
<p>
With coding agents producing more PRs than ever, this problem scales with your team. If your test suite is flaky, your PR throughput doesn&#39;t scale and it ends being the bottleneck.</p>
<p>
Tuist detects flaky tests in two ways:</p>
<ul>
  <li>
<strong>Test retries</strong>: When you use the <a href="https://github.com/gradle/test-retry-gradle-plugin">Test Retry plugin</a>, Tuist analyzes each attempt. If a test fails on some attempts but passes on others, it&#39;s automatically marked as flaky.  </li>
  <li>
<strong>Cross-run detection</strong>: Even without retries, Tuist compares results across different CI runs on the same commit. If a test passes in one run but fails in another, both runs are flagged.  </li>
</ul>
<p>
Once detected, flaky tests appear in your project&#39;s dashboard where you can track their flakiness rate and drill into individual failures. Tests are automatically cleared after 14 days of stability.</p>
<p>
  <img src="/marketing/images/blog/2026/03/02/gradle/flaky-runs.png" alt="Flaky runs analytics chart showing flaky test trends over the last 30 days">
</p>
<p>
And you don&#39;t have to stop at detection. With <strong>automatic quarantining</strong>, newly detected flaky tests are immediately isolated from your CI pipeline. The Gradle plugin fetches the quarantined test list before each test task and excludes them using Gradle&#39;s <code class="inline">excludeTestsMatching</code> filter. Your PRs stop getting blocked by tests that have nothing to do with your changes while you investigate the root cause.</p>
<h2 id="built-for-automation-and-agentic-workflows" tabindex="-1" class="marketing__blog_post__body__content__heading">
Built for automation and agentic workflows<a href="#built-for-automation-and-agentic-workflows" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Built for automation and agentic workflows"></a></h2>
<p>
All the data Tuist collects — build insights, test results, flaky test history — is accessible through the CLI and the API. This matters because it makes Tuist a natural fit for the growing world of AI-assisted development.</p>
<p>
For example, our <a href="https://docs.tuist.dev/en/guides/features/agentic-coding/skills">fix-flaky-tests skill</a> gives coding agents like Claude Code the context they need to actually fix flaky tests. The agent queries Tuist for flaky test data, analyzes failure patterns, identifies root causes, and applies targeted corrections. Coding agents are only as effective as the context you provide them with and Tuist provides the missing link for tackling these kinds of challenges.</p>
<h2 id="getting-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting started<a href="#getting-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting started"></a></h2>
<p>
First, <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist">install the Tuist CLI</a>. Then run <code class="inline">tuist init</code> in your Gradle project root and follow the interactive setup. The command handles authentication, project creation, and generates the configuration for you. Then apply the plugin in your <code class="inline">settings.gradle.kts</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
kotlin    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="kotlin">
plugins {
    id(&quot;dev.tuist&quot;) version &quot;0.2.2&quot;
}    </shiki-highlight>
  </div>
</div>
<p>
That&#39;s it. Build insights and test insights start flowing automatically, and enabling the remote cache is a one-liner in <code class="inline">gradle.properties</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
properties    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="properties">
org.gradle.caching=true    </shiki-highlight>
  </div>
</div>
<p>
For the full details, see the <a href="https://docs.tuist.dev/en/guides/install-gradle-plugin">Gradle plugin documentation</a>.</p>
<h2 id="android-specific-features" tabindex="-1" class="marketing__blog_post__body__content__heading">
Android-specific features<a href="#android-specific-features" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Android-specific features"></a></h2>
<p>
Beyond the Gradle plugin, Tuist also supports features that are particularly useful for Android teams.</p>
<h3 id="bundle-insights" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bundle insights<a href="#bundle-insights" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bundle insights"></a></h3>
<p>
As your app grows, so does your bundle size. Tuist supports analyzing both <code class="inline">.aab</code> (recommended) and <code class="inline">.apk</code> files:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist inspect bundle App.aab    </shiki-highlight>
  </div>
</div>
<p>
You get a detailed breakdown of your bundle and the bundle size tracked over time. When integrated with GitHub, Tuist posts bundle size analysis directly in your pull requests. You can also get notified directly in Slack with our <a href="https://docs.tuist.dev/en/guides/integrations/slack#alert-rules">Slack integration</a>, so your team gets notified about size regressions as soon as they happen, ensuring they get caught before they ship.</p>
<p>
  <img src="/marketing/images/blog/2026/03/02/gradle/bundle-insights.png" alt="Bundle size analysis of an Android app showing file breakdown by category">
</p>
<h2 id="you-don't-need-to-host-anything" tabindex="-1" class="marketing__blog_post__body__content__heading">
You don&#39;t need to host anything<a href="#you-don't-need-to-host-anything" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to You don't need to host anything"></a></h2>
<p>
One thing we hear from teams evaluating build infrastructure tools: &quot;We don&#39;t want to run more servers.&quot; We get it.</p>
<p>
With Tuist, you don&#39;t need to host anything. We host the infrastructure for you, regardless of team size. There&#39;s no Gradle remote cache server to maintain, no analytics database to provision, no artifact storage to manage. You install the plugin, authenticate, and everything works.</p>
<p>
For teams that do want more control, there are two self-hosting options:</p>
<ul>
  <li>
<strong>Self-host everything</strong>: Deploy the full Tuist server on your infrastructure. The whole server is <a href="https://github.com/tuist/tuist">source available</a>, so you can inspect exactly what&#39;s running. See the <a href="https://docs.tuist.dev/en/guides/server/self-host/install">self-hosting guide</a>.  </li>
  <li>
<strong>Self-host just the cache nodes</strong>: This is especially interesting for teams working from the office or using self-hosted CI runners. You can deploy lightweight cache nodes close to where builds happen while letting Tuist handle the server itself, which is more involved to self-host. See the <a href="https://docs.tuist.dev/en/guides/cache/self-host">cache self-hosting guide</a>.  </li>
</ul>
<h2 id="source-available-and-open" tabindex="-1" class="marketing__blog_post__body__content__heading">
Source available and open<a href="#source-available-and-open" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Source available and open"></a></h2>
<p>
The entire <a href="https://github.com/tuist/tuist">Tuist codebase</a> is source available, and a large part of it is MIT licensed. You can read the source, understand how your data is handled, and contribute if you want. Transparency is a core part of how we build.</p>
<p>
And since we dogfood everything we do, we&#39;re also using Tuist for our own Gradle-based projects and you can check out the public dashboards of these:</p>
<ul>
  <li>
<a href="https://tuist.dev/tuist/android">Tuist Android app</a>  </li>
  <li>
<a href="https://tuist.dev/tuist/gradle-plugin">Tuist Gradle plugin</a>  </li>
</ul>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
All of the Gradle features are currently <strong>free</strong> as our thank you to early supporters. Pricing for the remote cache will come later this year, but for now you can use <strong>everything</strong> mentioned here at no cost.</p>
<p>
We&#39;ll continue going deeper into build and test insights. We want to track more data to pinpoint build bottlenecks, monitor CPU usage, and bring native support for test sharding. We&#39;re also building a native Tuist Android app (releasing later this month) that will make accessing and running <a href="https://docs.tuist.dev/en/guides/features/previews">Tuist Previews</a> on Android devices seamless, just like the existing <a href="https://tuist.dev/download">macOS</a> and <a href="https://apps.apple.com/us/app/tuist/id6748460335">iOS</a> apps do for Apple platforms. If there&#39;s anything your team is missing from the dashboard, <a href="https://community.tuist.dev">let us know</a> and we can prioritize it.</p>
<p>
We&#39;re excited to bring everything we&#39;ve learned from scaling Apple platform builds to the Android ecosystem, and to keep growing both sides together.</p>
<p>
Reach out to us in our <a href="https://community.tuist.dev">community forum</a> or send us an email at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a>. We&#39;d love to hear how you&#39;re using Tuist with Gradle.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Our Swift CLI now runs on Linux ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist is no longer macOS-only. You can now run analytical workflows or leverage the upcoming Tuist Gradle support on Linux. ]]></summary>
      <link href="https://tuist.dev/blog/2026/02/16/linux"/>
      <id>https://tuist.dev/blog/2026/02/16/linux</id>
      <updated>Mon, 16 Feb 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist has started as a macOS-only tool. That made sense when its scope was Xcode project generation and building your projects for Apple platforms. But Tuist has grown well beyond that. We now offer build and test insights, flaky test detection, build caching, and more. And we&#39;re adding <a href="https://community.tuist.dev/t/tuist-is-coming-to-android/838">Gradle support</a>, for example, for Android projects. Restricting the CLI to macOS no longer reflects what Tuist does or where developers need it.</p>
<p>
That&#39;s why we&#39;re very excited to announce that the Tuist CLI runs on Linux.</p>
<h2 id="why-linux-matters" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why Linux matters<a href="#why-linux-matters" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why Linux matters"></a></h2>
<p>
There are three main reasons we invested in Linux support:</p>
<ul>
  <li>
    <p>
<strong>Gradle on Android:</strong> We&#39;re bringing Gradle project integration to Tuist. Android builds commonly run on Linux CI machines, and requiring macOS for a tool that manages Gradle projects would be a dealbreaker. Linux support makes Tuist viable for Android workflows out of the box.    </p>
  </li>
  <li>
    <p>
<strong>Analytical workflows on CI:</strong> Commands like <code class="inline">tuist test case list</code> don&#39;t need Xcode or macOS. They talk to the Tuist server, process data, and return results. Linux machines are typically much cheaper than macOS ones, so running analytical and data-ingestion workflows there is a straightforward cost saving.    </p>
  </li>
  <li>
    <p>
<strong>Agentic environments:</strong> AI coding agents are increasingly running in cloud environments that default to Linux. Whether it&#39;s an agent that checks build analytics, manages project settings, or automates test quarantining, it needs a CLI that runs where it lives. Linux support makes Tuist accessible in these agentic workflows without requiring a macOS VM.    </p>
  </li>
</ul>
<h2 id="supported-commands" tabindex="-1" class="marketing__blog_post__body__content__heading">
Supported commands<a href="#supported-commands" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Supported commands"></a></h2>
<p>
Not every command makes sense on Linux — commands like <code class="inline">tuist generate</code> or <code class="inline">tuist xcodebuild</code> inherently depend on Xcode and remain macOS-only. What does work on Linux are the commands that don&#39;t need Xcode: authentication, account and project management, analytical commands for browsing builds and test cases, cache configuration, and <code class="inline">tuist init</code> for scaffolding new projects. In short, anything that talks to the Tuist server or sets up your project works on Linux today.</p>
<h2 id="how-we-got-here" tabindex="-1" class="marketing__blog_post__body__content__heading">
How we got here<a href="#how-we-got-here" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How we got here"></a></h2>
<p>
Getting a Swift CLI to compile and run on Linux is not trivial. Here&#39;s how we approached it.</p>
<h3 id="modularization-and-incremental-migration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Modularization and incremental migration<a href="#modularization-and-incremental-migration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Modularization and incremental migration"></a></h3>
<p>
Before touching the Tuist CLI itself, we had already invested in Linux support across our open-source libraries, such as <a href="https://github.com/tuist/Noora">Noora</a>, our terminal UI framework, or <a href="https://github.com/tuist/FileSystem">FileSystem</a>, our file system abstraction. This meant the foundational layers were ready.</p>
<p>
When we started to add Linux support, we knew we wanted to do so gradually by cross-compiling individual modules instead of doing everything in a single PR. And while Tuist was already heavily modularized, we still had a couple of monolith modules that mixed platform-specific and platform-independent code. <code class="inline">TuistSupport</code>, our shared utility layer, was broken into focused modules like <code class="inline">TuistConstants</code>, <code class="inline">TuistEnvironment</code>, and <code class="inline">TuistLogging</code>. <code class="inline">TuistKit</code>, which contained all the command logic, was split into per-command modules: <code class="inline">TuistAuthCommand</code>, <code class="inline">TuistCacheCommand</code>, <code class="inline">TuistBuildCommand</code>, and so on. Once separated, each module could independently target Linux compilation without pulling in macOS-only dependencies. That not only allowed for a gradual migration, but it allowed us to use compiler directives like <code class="inline">#if os(macOS)</code> and <code class="inline">#if canImport(...)</code> sparingly, keeping the code easier to read and maintain.</p>
<h3 id="fully-static-binaries-with-musl" tabindex="-1" class="marketing__blog_post__body__content__heading">
Fully static binaries with musl<a href="#fully-static-binaries-with-musl" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Fully static binaries with musl"></a></h3>
<p>
Our first Linux builds linked the Swift standard library and system libraries like <code class="inline">libcurl</code> dynamically, meaning the binary required the Swift runtime and matching system libraries on the target machine. Instead, we switched to Swift&#39;s <a href="https://www.swift.org/documentation/articles/static-linux-getting-started.html">Static Linux SDK</a> which cross-compiles against <a href="https://musl.libc.org/">musl libc</a> to produce fully static binaries with zero shared library dependencies:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
swift sdk install https://download.swift.org/swift-6.1.2-release/static-sdk/swift-6.1.2-RELEASE/swift-6.1.2-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz
swift build --product tuist --configuration release --swift-sdk x86_64-swift-linux-musl    </shiki-highlight>
  </div>
</div>
<p>
The resulting binary runs identically on Ubuntu, Fedora, Alpine, or any other Linux distribution. No dynamic linker, no shared libraries, no Swift installation required. The trade-off is a larger binary since everything is bundled in, but for a CLI tool that&#39;s distributed once and run many times, portability is worth it.</p>
<p>
The switch to musl did require some code changes. The C library module is named <code class="inline">Musl</code> rather than <code class="inline">Glibc</code>, so platform imports became three-way:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
#if canImport(Glibc)
    import Glibc
    let systemGlob = Glibc.glob
#elseif canImport(Musl)
    import Musl
    let systemGlob = Musl.glob
#elseif canImport(Darwin)
    import Darwin
    let systemGlob = Darwin.glob
#endif    </shiki-highlight>
  </div>
</div>
<h3 id="distribution" tabindex="-1" class="marketing__blog_post__body__content__heading">
Distribution<a href="#distribution" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Distribution"></a></h3>
<p>
We wanted the installation experience on Linux to be identical to macOS. Tuist is installed via <a href="https://mise.jdx.dev/">mise</a>, so we updated the <a href="https://github.com/aquaproj/aqua-registry">aqua-registry</a> and <a href="https://github.com/jdx/mise/pull/8102">mise itself</a> to recognize Tuist&#39;s Linux binaries. The result is that installing Tuist on Linux is the same single command you&#39;re already used to from macOS:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mise use -g tuist    </shiki-highlight>
  </div>
</div>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
The Linux support is our first step outside of macOS and Apple platforms, but not the last one. We already have plans for support of:</p>
<ul>
  <li>
<strong>Gradle</strong>: We&#39;ll be officially releasing Gradle project integration soon, enabling Tuist to optimize and track Android builds.  </li>
  <li>
<strong>Windows</strong>: We&#39;d like to bring Tuist to Windows as well. However, some of our transitive dependencies, like <a href="https://github.com/apple/swift-nio/issues/2065">swift-nio</a> (used via our <a href="https://github.com/tuist/filesystem">FileSystem</a> library), don&#39;t yet support Windows. We&#39;re keeping an eye on upstream progress and will revisit this as the Swift-on-Windows ecosystem matures.  </li>
</ul>
<p>
If you&#39;re running CI on Linux or exploring cross-platform workflows, give the Linux CLI a try and let us know how it goes. Reach out to us in our <a href="https://community.tuist.dev">community forum</a> or send us an email at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a> for sharing your feedback</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Codex cut Mastodon iOS clean builds 80% ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We gave Codex the Mastodon iOS client and asked it to migrate the project to Tuist generated projects, enable caching, and benchmark the results. Here is what happened. ]]></summary>
      <link href="https://tuist.dev/blog/2026/02/02/migrating-mastodon-ios-to-tuist-with-codex"/>
      <id>https://tuist.dev/blog/2026/02/02/migrating-mastodon-ios-to-tuist-with-codex</id>
      <updated>Mon, 02 Feb 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
People have asked us many times why we haven&#39;t built an automated migration path to <a href="https://docs.tuist.dev/en/guides/features/projects">Tuist generated projects</a>. The honest answer is that real-world Xcode projects are messy. They are full of implicit configuration, one-off build settings, and decisions that made sense at the time but are hard to detect from the outside. For years, that kept migrations manual and made teams hesitant to adopt generated projects, even when they wanted the <a href="https://docs.tuist.dev/en/guides/develop/build/cache">module cache</a> and the productivity gains that come with it.</p>
<p>
We&#39;ve been thinking about this differently since coding agents became capable enough to hold context across long feedback loops. What if the agent could do the mechanical work of migration while we focus on defining the constraints and validating the output? If that works, Tuist handles the complexity of Xcode projects, agents handle the tool adoption, and developers get faster workflows without the friction of a manual migration.</p>
<p>
We decided to test this on the <a href="https://github.com/mastodon/mastodon-ios">Mastodon iOS client</a>. A real app with multiple frameworks, extensions, third-party dependencies, and all the quirks that come with a production codebase. The goal was a generated workspace that builds, runs, and benefits from caching. You can find the resulting project <a href="https://github.com/tuist/mastodon-ios-tuist">on GitHub</a>. We also wanted captured the process in a reusable <a href="https://docs.tuist.dev/en/guides/features/agentic-coding/skills">skill</a> that makes it easier for other teams to migrate without having to instruct the agent themselves on how to close the feedback loop.</p>
<h2 id="what-we-asked-codex-to-do" tabindex="-1" class="marketing__blog_post__body__content__heading">
What we asked Codex to do<a href="#what-we-asked-codex-to-do" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What we asked Codex to do"></a></h2>
<p>
We didn&#39;t hand Codex a step-by-step checklist. We gave it a set of outcomes: produce a Tuist-generated project that stays as close as possible to the original, integrate dependencies through Xcode project primitives so they can be cached as binaries, validate that the app actually launches on a simulator, and write a <code class="inline">skill.md</code> that captures the migration knowledge for future use.</p>
<p>
A migration like this isn&#39;t just about compiling. It requires understanding feedback loops, holding state across errors, and making judgment calls when things break. We used <a href="https://openai.com/codex/">Codex</a> 5.2 with GPT-5 as the underlying model because we wanted to test whether the model could handle that without constant human supervision.</p>
<h2 id="how-it-actually-went" tabindex="-1" class="marketing__blog_post__body__content__heading">
How it actually went<a href="#how-it-actually-went" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How it actually went"></a></h2>
<p>
The first step was establishing a baseline. The original Xcode project compiled and the app launched on the simulator. Having that baseline gave us a reference point for the benchmark and confirmed we were starting from something healthy.</p>
<p>
From there, the agent extracted build settings into <code class="inline">.xcconfig</code> files and wired them back into the target definitions in <code class="inline">Project.swift</code>. This follows our <a href="https://docs.tuist.dev/en/guides/features/projects/adoption/migrate/xcode-project">migration guidance</a>, which recommends xcconfig extraction because it preserves the settings hierarchy and keeps the manifest readable. Then it created the initial <code class="inline">Tuist.swift</code>, <code class="inline">Project.swift</code>, and <code class="inline">Tuist/Package.swift</code>, mapping each target into the Tuist graph.</p>
<p>
The first <code class="inline">tuist generate</code> was successful, but then things started breaking, which is exactly what happens in real migrations.</p>
<h3 id="the-missing-class-that-wasn't-missing" tabindex="-1" class="marketing__blog_post__body__content__heading">
The missing class that wasn&#39;t missing<a href="#the-missing-class-that-wasn't-missing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The missing class that wasn't missing"></a></h3>
<p>
The first failure was a missing <code class="inline">TimelineListViewController</code> referenced by <code class="inline">DiscoveryViewModel</code>. The agent had excluded a directory called &quot;In Progress New Layout and Datamodel&quot; because it looked like unfinished work. Reasonable assumption, wrong conclusion. The class lived in that directory, and the original Xcode project included it while excluding only one specific file from the folder.</p>
<p>
The agent went back to the pbx structure, inspected the exception set, and adjusted the source glob to mirror exactly what the original project did. After the fix, those errors were gone.</p>
<h3 id="resources,-sources,-and-boundary-confusion" tabindex="-1" class="marketing__blog_post__body__content__heading">
Resources, sources, and boundary confusion<a href="#resources,-sources,-and-boundary-confusion" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Resources, sources, and boundary confusion"></a></h3>
<p>
The second round of errors was subtler. <code class="inline">.intentdefinition</code> files were being treated as resources when they needed to be sources. <code class="inline">.xcstrings</code> files were getting shadowed by <code class="inline">.strings</code> globs under a broader resource directory. Settings bundles were being treated as individual files rather than folder references.</p>
<p>
Each of these was straightforward to fix once identified, but they are a good illustration of why migrations are tricky. The mistakes aren&#39;t about code logic. They are about boundaries: where sources end and resources begin, what counts as a file versus a folder reference, which build phase something belongs to.</p>
<h3 id="making-it-launch" tabindex="-1" class="marketing__blog_post__body__content__heading">
Making it launch<a href="#making-it-launch" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Making it launch"></a></h3>
<p>
After the workspace built successfully, the agent installed the app on the simulator and launched it. It crashed immediately with an unrecognized selector, <code class="inline">processCompletedCount</code>, coming off <code class="inline">NSUserDefaults</code>. Since Tuist integrates dependencies as Xcode-native targets and defaults to static linking, the linker was stripping object files that contained only Objective-C categories without class definitions. The category methods simply disappeared from the binary. As <a href="https://developer.apple.com/library/archive/qa/qa1490/_index.html">Apple Technical Q&amp;A QA1490</a> explains, this is expected behavior. Our <a href="https://docs.tuist.dev/en/guides/features/projects/dependencies#objectivec-dependencies">dependency documentation</a> covers this in more detail.</p>
<p>
The fix was adding <code class="inline">-ObjC</code> to <code class="inline">OTHER_LDFLAGS</code> in the shared project xcconfig, which forces the linker to load all object files from static libraries. After that, the app launched and stayed up. This is why it&#39;s important to instruct the agent to actually run the app on a simulator and tell it how to do so. That way it can detect runtime failures on its own and close the feedback loop without human intervention.</p>
<h2 id="unlocking-cache" tabindex="-1" class="marketing__blog_post__body__content__heading">
Unlocking cache<a href="#unlocking-cache" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Unlocking cache"></a></h2>
<p>
The whole point of migrating was to unlock caching. A modular generated project is nice, but what we really wanted was fast clean builds by default.</p>
<p>
Once everything compiled and ran, <code class="inline">tuist cache</code> warmed the binaries and <code class="inline">tuist setup cache</code> enabled the <a href="https://docs.tuist.dev/en/guides/features/cache">Xcode compilation cache</a>.</p>
<h2 id="the-benchmark" tabindex="-1" class="marketing__blog_post__body__content__heading">
The benchmark<a href="#the-benchmark" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The benchmark"></a></h2>
<p>
We used <a href="https://github.com/sharkdp/hyperfine">hyperfine</a> for repeatability. Both scenarios ran three times as clean builds with <code class="inline">xcodebuild clean build</code> and a dedicated <code class="inline">-derivedDataPath</code> per scenario.</p>
<p>
<strong>No-cache baseline:</strong> the Tuist-generated workspace with the cache profile set to <code class="inline">none</code>, derived data wiped between runs, and Xcode compilation cache disabled.</p>
<p>
<strong>Cached build:</strong> the <code class="inline">all-possible</code> cache profile so only the app and its extensions built from source, with Xcode compilation cache enabled. Before each run, local binaries and the compilation cache directory were removed so artifacts were pulled from the remote cache.</p>
<p>
The commands looked like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist setup cache
tuist cache

hyperfine --runs 3 --warmup 1 \
  --prepare &#39;rm -rf DerivedData-NoCache &amp;&amp; tuist generate --no-open --cache-profile none&#39; \
  &#39;xcodebuild clean build -workspace Mastodon-Tuist.xcworkspace -scheme Mastodon -configuration Debug -destination &quot;platform=iOS Simulator,name=iPhone 17&quot; -derivedDataPath ./DerivedData-NoCache COMPILATION_CACHE_ENABLE_CACHING=NO COMPILATION_CACHE_ENABLE_PLUGIN=NO&#39;

hyperfine --runs 3 --warmup 1 \
  --prepare &#39;rm -rf DerivedData-Cache ~/.tuist/Binaries ~/Library/Developer/Xcode/CompilationCache.noindex ~/Library/Caches/com.apple.dt.Xcode/CompilationCache.noindex &amp;&amp; tuist generate --no-open --cache-profile all-possible&#39; \
  &#39;xcodebuild clean build -workspace Mastodon-Tuist.xcworkspace -scheme Mastodon -configuration Debug -destination &quot;platform=iOS Simulator,name=iPhone 17&quot; -derivedDataPath ./DerivedData-Cache COMPILATION_CACHE_ENABLE_CACHING=YES COMPILATION_CACHE_ENABLE_PLUGIN=YES&#39;    </shiki-highlight>
  </div>
</div>
<p>
<strong>Results:</strong></p>
<table>
  <thead>
    <tr>
      <th style="text-align: left;">
Scenario      </th>
      <th style="text-align: left;">
Mean      </th>
      <th style="text-align: left;">
Min      </th>
      <th style="text-align: left;">
Max      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left;">
No cache      </td>
      <td style="text-align: left;">
110.8s      </td>
      <td style="text-align: left;">
95.5s      </td>
      <td style="text-align: left;">
132.8s      </td>
    </tr>
    <tr>
      <td style="text-align: left;">
Cached      </td>
      <td style="text-align: left;">
22.3s      </td>
      <td style="text-align: left;">
21.0s      </td>
      <td style="text-align: left;">
24.5s      </td>
    </tr>
  </tbody>
</table>
<p>
That is a <strong>4.98x speedup</strong> and a <strong>79.9% reduction</strong> in clean build time.</p>
<p>
It&#39;s worth mentioning that cache effectiveness depends on how modularized the project already is. If most of your code lives in a single app target, there is less to cache. Mastodon has several internal frameworks, but the app target itself is still large. Teams that invest in smaller targets and clearer module boundaries should see even larger gains.</p>
<h2 id="the-skill" tabindex="-1" class="marketing__blog_post__body__content__heading">
The skill<a href="#the-skill" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The skill"></a></h2>
<p>
The most valuable output of this migration isn&#39;t the Mastodon workspace itself. It is the skill file that captures how to do this again.</p>
<p>
The agent wrote <code class="inline">skill.md</code> as a migration guide that starts where a real engineer would start: with a baseline build, a target inventory, and a realistic set of constraints. It focuses on what tends to go wrong, how to detect it, and how to keep the generated project aligned with the original. It intentionally avoids caching instructions so it stays focused on migration mechanics. The published version of that skill lives at <a href="https://tuist.dev/skills/migrate/SKILL.md">tuist.dev/skills/migrate/SKILL.md</a>, and the installation steps are documented in our <a href="https://docs.tuist.dev/en/guides/features/agentic-coding/skills">Skills guide</a>.</p>
<h2 id="what-we-took-away-from-this" tabindex="-1" class="marketing__blog_post__body__content__heading">
What we took away from this<a href="#what-we-took-away-from-this" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What we took away from this"></a></h2>
<p>
A coding agent took a production iOS app, migrated it to generated projects, fixed a few issues along the way, confirmed the app runs, and got clean builds down by 80%.</p>
<p>
Manual migrations can take days or even weeks, which is why many teams never got around to it. This one took a few hours of agent time. With agents doing the heavy lifting, the cost of adopting generated projects drops significantly. Your developers wait less on builds, and your CI stops redoing work that hasn&#39;t changed.</p>
<p>
We&#39;re going to keep using this skill on more projects and refining it as we go.</p>
<h2 id="try-it-on-your-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
Try it on your project<a href="#try-it-on-your-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Try it on your project"></a></h2>
<p>
If you want to migrate your project, you can get started with the <a href="https://docs.tuist.dev/en/guides/features/agentic-coding/skills">migration skill</a> today. Point your coding agent at it and let it work through the feedback loop. If you run into issues or have feedback on the skill, we&#39;d love to hear about it at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a> or in our <a href="https://community.tuist.dev">community forum</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Stop Flaky Tests from Blocking Your PRs ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Flaky tests waste engineering hours and block PR throughput. Learn how Tuist automatically detects, tracks, and quarantines flaky tests so your team can ship faster. ]]></summary>
      <link href="https://tuist.dev/blog/2026/01/27/flaky-tests"/>
      <id>https://tuist.dev/blog/2026/01/27/flaky-tests</id>
      <updated>Tue, 27 Jan 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
You open a pull request. The CI runs. It fails. You look at the failing test and it has nothing to do with your changes. You click retry. This time it passes. But now there&#39;s a merge conflict because someone else landed their changes while you were waiting. You resolve the conflict, push again, and the CI fails on a <em>different</em> unrelated test. Another retry. Another wait. By the time your one-line fix actually lands, you&#39;ve lost an hour to tests that aren&#39;t actually testing your code.</p>
<p>
This scenario plays out thousands of times a day across engineering teams everywhere. And the worst part? Most organizations have no idea how much time they&#39;re losing. Flaky tests are a silent productivity killer that compounds over time, eroding trust in your test suite and frustrating developers who just want to ship their work.</p>
<h2 id="the-hidden-cost-of-flaky-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
The hidden cost of flaky tests<a href="#the-hidden-cost-of-flaky-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The hidden cost of flaky tests"></a></h2>
<p>
The direct cost is easy to see: wasted CI minutes, wasted developer time, delayed merges. But the indirect cost is far more damaging.</p>
<p>
When flaky tests become common, developers stop trusting the test suite. &quot;It&#39;s probably just that flaky test&quot; becomes the default assumption when CI fails. Real bugs slip through because the signal has been drowned out by noise. The test suite that was supposed to catch regressions before they reach production now gets ignored because it fails too often due to tests being unreliable.</p>
<p>
And unlike a slow test suite or a missing feature, flaky tests are invisible in aggregate. No dashboard shows you &quot;your team lost 47 hours this month to spurious failures.&quot; No alert fires when trust in your CI erodes past the point of usefulness. The cost accumulates silently until someone finally asks why PRs take so long to land.</p>
<h2 id="why-this-matters-more-than-ever" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why this matters more than ever<a href="#why-this-matters-more-than-ever" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why this matters more than ever"></a></h2>
<p>
With the rise of AI coding agents like <a href="https://claude.com/product/claude-code">Claude Code</a> and <a href="https://openai.com/codex/">Codex</a>, teams are producing more PRs than ever before. Agents can write code faster than humans, but they still have to wait for CI like everyone else. If your test suite is flaky, you&#39;ve just created a bottleneck that scales with your agent usage. The more PRs you open, the more time gets wasted on spurious failures.</p>
<p>
If your test suite is flaky, your PR throughput doesn&#39;t scale with your team. It becomes the bottleneck.</p>
<h2 id="detecting-flaky-tests-automatically" tabindex="-1" class="marketing__blog_post__body__content__heading">
Detecting flaky tests automatically<a href="#detecting-flaky-tests-automatically" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Detecting flaky tests automatically"></a></h2>
<p>
No developer should have to manually track which tests are unreliable. Flaky test detection builds on top of <a href="https://docs.tuist.dev/en/guides/features/test-insights">Test Insights</a>, so if you&#39;re already using it, you get flaky detection automatically. Tuist detects flaky tests in two ways:</p>
<h3 id="retry-based-detection" tabindex="-1" class="marketing__blog_post__body__content__heading">
Retry-based detection<a href="#retry-based-detection" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Retry-based detection"></a></h3>
<p>
When you run tests with Xcode&#39;s retry functionality using <code class="inline">-retry-tests-on-failure</code> or <code class="inline">-test-iterations</code>, Tuist analyzes the results of each attempt. If a test fails on the first attempt but passes on the retry, Tuist automatically marks it as flaky.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist xcodebuild test \
  -scheme MyScheme \
  -retry-tests-on-failure \
  -test-iterations 3    </shiki-highlight>
  </div>
</div>
<p>
This catches flakiness within a single CI run rather than needing multiple runs to detect it. We recommend enabling test retries if you haven&#39;t already.</p>
<h3 id="cross-run-detection" tabindex="-1" class="marketing__blog_post__body__content__heading">
Cross-run detection<a href="#cross-run-detection" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Cross-run detection"></a></h3>
<p>
Even without retries, Tuist can detect flaky tests by comparing results across different CI runs on the same commit. If a test passes in one CI run but fails in another for the same commit SHA, both runs are marked as flaky.</p>
<p>
This catches the particularly elusive flaky tests that don&#39;t fail consistently enough to be caught by retries but still cause intermittent CI failures that waste your team&#39;s time.</p>
<p>
Once detected, flaky tests appear in your project&#39;s Flaky Tests page, where you can see the flakiness rate, track flaky runs over time, and drill into individual test cases.</p>
<p>
  <img src="/marketing/images/blog/2026/01/27/flaky-tests/flaky-tests-page.png" alt="Flaky Tests page showing detected flaky tests with their flakiness rates">
</p>
<h2 id="stop-flaky-tests-from-blocking-your-prs" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stop flaky tests from blocking your PRs<a href="#stop-flaky-tests-from-blocking-your-prs" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stop flaky tests from blocking your PRs"></a></h2>
<p>
Knowing which tests are flaky doesn&#39;t help if they&#39;re still failing your CI. How do you keep shipping while you investigate and fix them?</p>
<p>
This is where quarantining comes in. When you quarantine a test, you&#39;re marking it as &quot;known flaky&quot; and excluding it from your CI runs entirely. This prevents flaky failures from blocking your PRs while you work on a fix. You can enable automatic quarantine in your project&#39;s Automations settings so newly detected flaky tests are isolated immediately, or manually quarantine tests from the test case detail page when you want more control.</p>
<h3 id="skipping-quarantined-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
Skipping quarantined tests<a href="#skipping-quarantined-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Skipping quarantined tests"></a></h3>
<p>
To actually skip quarantined tests in your CI, use the <code class="inline">tuist test case list</code> command with the <code class="inline">--skip-testing</code> flag:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
xcodebuild test \
  -scheme MyScheme \
  $(tuist test case list --skip-testing)    </shiki-highlight>
  </div>
</div>
<p>
This fetches all quarantined test identifiers and formats them as xcodebuild arguments. Your CI becomes reliable again, PRs stop getting blocked by unrelated failures, and your team stays productive while you fix the underlying issues.</p>
<p>
Once you&#39;ve shipped a fix, unmark the test as flaky from the test case detail page. If it becomes flaky again, Tuist will detect it and notify you.</p>
<h2 id="stay-informed-with-slack-notifications" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stay informed with Slack notifications<a href="#stay-informed-with-slack-notifications" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stay informed with Slack notifications"></a></h2>
<p>
You don&#39;t want to find out about flaky tests by having them block a critical PR. With the <a href="https://docs.tuist.dev/en/guides/integrations/slack">Slack integration</a>, you get notified the moment a test becomes flaky.</p>
<img src="/marketing/images/blog/2026/01/27/flaky-tests/slack-alert.png" alt="Slack notification showing a new flaky test detected" style="max-width: 500px;">
<p>
The notification includes direct links to investigate the flaky test case, so you can start debugging immediately rather than waiting until it blocks someone.</p>
<p>
Additionally, when a PR has a flaky test run, it gets surfaced directly in the Tuist PR comment. The &quot;Flaky Tests&quot; section shows a summary of flaky tests per scheme with links to view all flaky runs without leaving your pull request.</p>
<p>
  <img src="/marketing/images/blog/2026/01/27/flaky-tests/pr-comment.png" alt="Flaky Tests in PR Comment">
</p>
<h2 id="getting-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting started<a href="#getting-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting started"></a></h2>
<p>
To start detecting flaky tests, you need <a href="https://docs.tuist.dev/en/guides/features/test-insights">Test Insights</a> configured for your project.</p>
<p>
Once Test Insights is running:</p>
<ol>
  <li>
Enable test retries in your CI with <code class="inline">-retry-tests-on-failure</code>  </li>
  <li>
Update your CI to skip quarantined tests using <code class="inline">tuist test case list --skip-testing</code>  </li>
  <li>
Set up <a href="https://docs.tuist.dev/en/guides/integrations/slack#flaky-test-alerts">Slack alerts</a> to get notified when new flaky tests are detected  </li>
</ol>
<p>
For detailed configuration options, see the <a href="https://docs.tuist.dev/en/guides/features/test-insights/flaky-tests">Flaky Tests documentation</a>.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
We&#39;re continuing to build on flaky test detection with features that further streamline your workflow:</p>
<ul>
  <li>
<strong>Issue tracker integration</strong>: When a new flaky test is detected, Tuist will be able to automatically create an issue in your tracker. When the issue is resolved, the test case gets unmarked as flaky, keeping everything in sync.  </li>
  <li>
<strong>Sharding</strong>: To further increase CI throughput, sharding lets you run your test suite across multiple machines in parallel. Since Tuist already knows the average duration of each test case, we can create balanced shards that all finish around the same time.  </li>
</ul>
<p>
What would you like to see next? Reach out to us in our <a href="https://community.tuist.dev">community forum</a> or send us an email at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a>. Your feedback shapes what we build.</p>
<h2 id="stop-the-cycle" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stop the cycle<a href="#stop-the-cycle" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stop the cycle"></a></h2>
<p>
Flaky tests don&#39;t just waste time. They erode trust in your test suite, slow down your release cycle, and compound developer frustration. Every retry is a context switch. Every false failure is a distraction from real work.</p>
<p>
With automatic detection, quarantining, and notifications, Tuist turns flaky tests from an invisible drain on productivity into a visible, manageable problem. You can see exactly which tests are unreliable, stop them from blocking your PRs, and fix them on your own schedule rather than in the heat of a blocked deployment.</p>
<p>
Your test suite should give you confidence, not anxiety. <a href="https://docs.tuist.dev/en/guides/features/test-insights/flaky-tests">Get on top of your flaky tests</a> and stop wasting time on retries.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ From reactive to proactive with the new Slack integration ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Stop finding out about build regressions from frustrated teammates. Let Tuist notify you in Slack the moment something goes wrong. ]]></summary>
      <link href="https://tuist.dev/blog/2026/01/12/slack-integration"/>
      <id>https://tuist.dev/blog/2026/01/12/slack-integration</id>
      <updated>Mon, 12 Jan 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
How does your team typically discover that build times have regressed? If you&#39;re like most teams, it goes something like this: a few days after a problematic change lands, engineers start complaining in Slack that builds feel slower. Someone eventually investigates, sifts through dozens of merged PRs, and tries to pinpoint which change caused the regression. Meanwhile, the entire team has been less productive—without anyone realizing it.</p>
<p>
This reactive approach to project health is the default across our industry. Even if you collect data, such as by using <a href="https://docs.tuist.dev/en/guides/features/insights">Tuist Insights</a>, unless someone actively checks dashboards, regressions slip through unnoticed and impact your team for way longer than they should.</p>
<p>
<strong>We think there&#39;s a better way.</strong> Instead of waiting for problems to become obvious, what if your tools could surface issues the moment they happen?</p>
<h2 id="bringing-insights-to-where-your-team-already-works" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bringing insights to where your team already works<a href="#bringing-insights-to-where-your-team-already-works" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bringing insights to where your team already works"></a></h2>
<p>
This is why we&#39;re introducing two new complementary features that integrate with Slack: <strong>daily reports</strong> and <strong>alert rules</strong>.</p>
<p>
With these, Tuist becomes proactive. Rather than requiring you to remember to check dashboards, it delivers the insights that matter directly to your Slack channels where your team already communicates.</p>
<h2 id="daily-reports" tabindex="-1" class="marketing__blog_post__body__content__heading">
Daily reports<a href="#daily-reports" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Daily reports"></a></h2>
<p>
Daily reports give your team a pulse check on your project&#39;s health. Each morning (or whenever you configure), Tuist sends a summary to your chosen Slack channel with key metrics:</p>
<ul>
  <li>
Build duration trends  </li>
  <li>
Test duration trends  </li>
  <li>
Cache hit rate  </li>
  <li>
Selective test effectiveness  </li>
  <li>
Bundle size  </li>
</ul>
<img src="/marketing/images/blog/2026/01/12/slack-integration/report.png" alt="A Slack report message showing build metrics with trend indicators" style="max-width: 500px;">
<p>
Each metric includes a trend indicator showing how it compares to the previous period. Is your p90 build time creeping up? Or your cache hit rate dropping? Tuist reports keep you up-to-date.</p>
<h2 id="alert-rules" tabindex="-1" class="marketing__blog_post__body__content__heading">
Alert rules<a href="#alert-rules" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Alert rules"></a></h2>
<p>
While reports are great for staying informed, some regressions need immediate attention. Alert rules let you define trigger notifications when something significant changes.</p>
<p>
For example, you might configure an alert that fires when the p90 build duration increases by more than 20% compared to the previous 100 builds or when the cache hit rate drops by 30%.</p>
<img src="/marketing/images/blog/2026/01/12/slack-integration/alert.png" alt="A Slack alert notification showing a build time regression" style="max-width: 500px;">
<p>
When an alert triggers, you get a Slack notification with the specific metric that regressed, the magnitude of the change, and links to investigate further. No more sifting through a week&#39;s worth of PRs to find the culprit, you&#39;ll know something went wrong within hours of the change landing. And a 24-hour cooldown prevents notification fatigue when a metric stays elevated, so you won&#39;t get spammed while investigating an issue.</p>
<h2 id="why-this-matters" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why this matters<a href="#why-this-matters" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why this matters"></a></h2>
<p>
The cost of a build time regression isn&#39;t just the extra seconds or minutes each build takes. It&#39;s the compounding effect across your entire team, multiplied by every build they run, every day the regression goes undetected. A 20% build time increase that goes unnoticed for a week can translate to hours or days of lost productivity. Not even mentioning the frustration and context-switching that slow builds cause.</p>
<p>
<strong>Proactive monitoring turns unknown unknowns into known issues.</strong> You can&#39;t fix problems you don&#39;t know about, and the longer they persist, the harder they become to diagnose.</p>
<h2 id="getting-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting started<a href="#getting-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting started"></a></h2>
<p>
To connect Slack to your Tuist project:</p>
<ol>
  <li>
Connect your Slack workspace in the Integrations tab  </li>
  <li>
Configure reports and alert rules in your project&#39;s notification settings  </li>
</ol>
<p>
  <img src="/marketing/images/blog/2026/01/12/slack-integration/notifications-settings.png" alt="The notifications settings page showing Slack configuration options">
</p>
<p>
For detailed setup instructions, including configuration options and on-premise installation, see the <a href="https://docs.tuist.dev/en/guides/integrations/slack">Slack integration documentation</a>.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
This is just the beginning of making Tuist more proactive. We&#39;re working on:</p>
<ul>
  <li>
<strong>Email notifications</strong>: not everyone lives in Slack, so we&#39;re adding the option to receive reports and alerts via email  </li>
  <li>
<strong>Flaky test alerts</strong>: as we build out flaky test detection, you&#39;ll be able to get notified when a flaky test is introduced, so you can address it before it starts causing spurious CI failures  </li>
</ul>
<p>
We&#39;re also eager to hear from you. What other events would you want to be notified about? What metrics matter most to your team? Let us know in our <a href="https://community.tuist.dev">community forum</a> as your feedback shapes what we build next.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Previews: SDK and Tracks for app previews ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Keep everyone on the latest app previews with the Tuist SDK and Tracks. ]]></summary>
      <link href="https://tuist.dev/blog/2026/01/02/previews-sdk-and-tracks"/>
      <id>https://tuist.dev/blog/2026/01/02/previews-sdk-and-tracks</id>
      <updated>Fri, 02 Jan 2026 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Over a year ago, we <a href="/blog/2024/08/06/url-centric-collaboration">introduced Tuist Previews</a> with a simple premise: sharing an app preview should be as easy as sending a link. The traditional flow of building, signing, and pushing to TestFlight was too cumbersome for quick feedback loops.</p>
<p>
Initially, we focused on minimizing friction for developers, introducing features like <a href="https://docs.tuist.dev/en/guides/features/previews#pullmerge-request-comments">posting comments directly in your pull requests</a>, allowing anyone to click a link and start testing without checking out a branch or waiting for a local build.</p>
<p>
But as teams adopted previews, it became clear we needed to expand our primary audience beyond engineers. Product managers wanted to see features before they shipped. QA teams needed consistent access to the latest builds. Leadership wanted to stay informed about what&#39;s coming.</p>
<p>
Today, we&#39;re taking the first steps in that direction with the new <strong>Tuist SDK</strong> and <strong>tracks</strong>.</p>
<h2 id="the-tuist-sdk:-in-app-update-notifications" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Tuist SDK: In-app update notifications<a href="#the-tuist-sdk:-in-app-update-notifications" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Tuist SDK: In-app update notifications"></a></h2>
<p>
Here&#39;s a common problem: you share a preview with a tester, they find an issue, you fix it and share a new preview. But the tester is still using the old build. They don&#39;t know a new version is available.</p>
<p>
The <a href="https://github.com/tuist/sdk">Tuist SDK</a> solves this by enabling your app to detect when a newer preview is available and notify users. Add the SDK to your project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
.package(url: &quot;https://github.com/tuist/sdk&quot;, .upToNextMajor(from: &quot;0.1.0&quot;))    </shiki-highlight>
  </div>
</div>
<p>
Then start monitoring for updates:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import TuistSDK

struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .task {
                    TuistSDK(
                        fullHandle: &quot;myorg/myapp&quot;,
                        apiKey: &quot;your-api-key&quot;
                    )
                    .monitorPreviewUpdates()
                }
        }
    }
}    </shiki-highlight>
  </div>
</div>
<p>
When a newer preview is available, the SDK will present an alert prompting the user to update:</p>
<img alt="Preview update alert" src="/marketing/images/blog/2026/01/02/previews-sdk-and-tracks/preview-update-alert.png" style="max-width: 300px;">
<blockquote>
  <p>
Update checking is automatically disabled on simulators and App Store builds, so you don&#39;t need to worry about conditional compilation.  </p>
</blockquote>
<p>
For more control, you can perform a single update check instead of continuous monitoring:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let sdk = TuistSDK(
    fullHandle: &quot;myorg/myapp&quot;,
    apiKey: &quot;your-api-key&quot;
)

if let preview = try await sdk.checkForUpdate() {
    print(&quot;New version available: \(preview.version ?? &quot;unknown&quot;)&quot;)
}    </shiki-highlight>
  </div>
</div>
<h2 id="tracks:-control-which-updates-to-notify-about" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tracks: Control which updates to notify about<a href="#tracks:-control-which-updates-to-notify-about" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tracks: Control which updates to notify about"></a></h2>
<p>
By default, the SDK checks for updates within the same git branch. A preview built from <code class="inline">main</code> will only notify about newer previews also built from <code class="inline">main</code>. This works well for PR-based workflows, but what about nightly builds, beta releases, or internal testing that aren&#39;t tied to a specific branch?</p>
<p>
Tracks let you organize previews into named groups and control which updates the SDK notifies about:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist share App --track beta
tuist share App --track nightly    </shiki-highlight>
  </div>
</div>
<p>
Tracks are lazily created – specify a track name and it will be created automatically if it doesn&#39;t exist. When you share a preview with <code class="inline">--track beta</code>, the SDK will only notify users about newer previews on the <code class="inline">beta</code> track.</p>
<p>
This is useful for several scenarios:</p>
<ul>
  <li>
<strong>Beta testing</strong>: Share stable builds with external testers on a <code class="inline">beta</code> track, keeping them on vetted releases rather than every commit  </li>
  <li>
<strong>Nightly builds</strong>: Automate nightly builds to a <code class="inline">nightly</code> track for internal QA  </li>
  <li>
<strong>Feature demos</strong>: Create a <code class="inline">demo</code> track for product reviews and stakeholder presentations  </li>
</ul>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
We&#39;re excited to take previews even further. We will soon start working on <a href="https://github.com/tuist/tuist/issues/8940">distribution groups</a> – the ability to define groups of users who should receive specific previews. You will be able to add your QA team to a <code class="inline">qa</code> group and having them automatically notified whenever a new preview is shared to the <code class="inline">nightly</code> track.</p>
<p>
We&#39;re also exploring Android support. As previews expand beyond engineering, teams expect a single way to share their apps – regardless of platform. A product manager shouldn&#39;t need different tools to test iOS and Android builds. QA teams shouldn&#39;t have to learn separate workflows. With Android support, you&#39;d share previews the same way across both platforms, and testers would receive updates through the same SDK. If your team builds for both platforms and you&#39;re interested in bringing previews to Android, <a href="mailto:contact@tuist.dev">reach out to us</a> – we&#39;d love to hear about your use case.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist in 2025: Building for the Long Game ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ How we went from a project generator to a productivity platform, grew the team, shipped more than ever, and discovered what sustainable developer tooling really means ]]></summary>
      <link href="https://tuist.dev/blog/2025/12/24/wrapped"/>
      <id>https://tuist.dev/blog/2025/12/24/wrapped</id>
      <updated>Wed, 24 Dec 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
2025 is almost over, and what a perfect time to reflect on what the year has meant for Tuist. We thought for a while about what the best format would be for this, and the one thing we were sure about is that we didn&#39;t want it to be the classic wrapped kind of structure that has spread across all platforms. Even LinkedIn has it these days. Who would have thought? We thought we&#39;d give it a personal touch.</p>
<h2 id="a-different-model" tabindex="-1" class="marketing__blog_post__body__content__heading">
A different model<a href="#a-different-model" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A different model"></a></h2>
<p>
We&#39;ve been thinking a lot about what makes software companies sustainable. Closed-source software has a straightforward playbook: create artificial scarcity and churn. Place features behind paywalls, require sales calls, deprecate things that work fine to push upgrades. It&#39;s not pretty, but it works.</p>
<p>
Open source breaks that playbook. When anyone can run your code, you can&#39;t manufacture scarcity. You need a different model. For Tuist, that meant the product had to take a different shape, solving problems where the server and infrastructure play a more important role. The value we charge for isn&#39;t the software itself, but running it fast, reliably, and securely. Think of how <a href="https://supabase.com">Supabase</a> contributes to <a href="https://www.postgresql.org">PostgreSQL</a> and hosts it as a service. Or how <a href="https://grafana.com">Grafana</a> built an empire around open-source observability tools. <a href="https://gitlab.com">GitLab</a> proved this at scale: they built an $11B business while keeping developers&#39; trust by making community engagement a company-wide priority. The software is free. The operational excellence is the product.</p>
<p>
We began transforming Tuist from a tool where most value lived in a client CLI, to one where more value lives in the server and eventually infrastructure. Organizations can pay us to run and scale their productivity infrastructure fast, safely, and reliably. We want most if not all of it to be open source and available for anyone to run locally. This year we <a href="https://tuist.dev/blog/2025/07/08/server-fcl">made the server source available</a>, and that felt like coming home. Openness eliminates barriers and makes you more accountable, leading to a much better product. When you work in the open, the community keeps you honest.</p>
<h2 id="growing-the-team" tabindex="-1" class="marketing__blog_post__body__content__heading">
Growing the team<a href="#growing-the-team" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Growing the team"></a></h2>
<p>
We knew we couldn&#39;t do this alone, so we welcomed <a href="https://github.com/cschmatzler">Chris</a> and <a href="https://github.com/asmitbm">Asmit</a> to the team. Chris brought tons of expertise working with web services powered by Elixir. Asmit&#39;s design skills would elevate Tuist&#39;s visual identity to a new level. We firmly believed that with our taste and ability to build great developer experiences, multiplied by how they&#39;d be presented to users thanks to gorgeous design, and spiced with open source, we&#39;d end up with a recipe that&#39;s unique in its space. We still believe that.</p>
<p>
Design is often undervalued in developer tools. There&#39;s this implicit assumption that developers don&#39;t care about aesthetics, that function trumps form. We think this is wrong. Good design is about clarity, and clarity is about respect for the user&#39;s time and attention.</p>
<p>
We designed and implemented a design system called <a href="https://github.com/tuist/noora">Noora</a> for both Elixir with Phoenix LiveView and Swift for the terminal. It got highlighted on <a href="https://www.swift.org/get-started/command-line-tools/">Apple&#39;s new Swift website</a>, which was a proud moment. We <a href="/blog/2025/04/17/meet-new-tuist">overhauled our dashboard</a>, redesigned our marketing site, and <a href="/blog/2025/06/10/open-sourcing-noora-for-the-web">open sourced Noora for the web</a> including all the Figma design files. We believe design systems should be a commodity, not a competitive advantage to be hoarded. This is how we contribute to the commons.</p>
<h2 id="what-we-shipped" tabindex="-1" class="marketing__blog_post__body__content__heading">
What we shipped<a href="#what-we-shipped" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What we shipped"></a></h2>
<p>
With that foundation in place, we shipped a lot with a team of 3.5 (the 0.5 was me, juggling business and housekeeping duties like <a href="/blog/2025/04/03/soc2">getting SOC 2 certified</a>). We built <a href="/blog/2025/11/26/opening-registry">a Swift package registry</a> and made it publicly available without requiring an account. We brought <a href="/blog/2025/11/17/smart-before-fast">build insights</a> and <a href="/blog/2025/12/03/test-insights">test insights</a>. We added support for <a href="/blog/2025/10/22/xcode-cache">Xcode cache</a> that works with any Xcode project. Our previews got better with <a href="/changelog#2025.12.17-preview-tracks-and-sdk">tracks</a> and a <a href="/blog/2025/07/22/tuist-ios-app">native iOS app</a>. We built <a href="/blog/2025/08/11/tuist-ai-whitepaper">Tuist QA</a>, which uses AI agents to test your previews. We shipped bundle analysis with a gorgeous dependency graph. If you look at Tuist at the end of 2025, it has nothing to do with the one we had at the beginning of the year.</p>
<p>
But here&#39;s what matters more than the list: <strong>most of these solutions work with your existing Xcode projects</strong>. You don&#39;t need to use <a href="https://docs.tuist.dev/en/guides/features/projects">generated projects</a>. You don&#39;t need to adopt a new project format. Most features can be adopted with a single line of code or command. This is intentional. We believe the best tools are the ones that meet you where you are. That said, generated projects remain the best option for scaling modular codebases—module caching alone can transform build times in large projects. Many still think of Tuist as a project generator, or as a Swift version of other project generation tools. It&#39;s fine! We&#39;re here to remind you. If you need a definition, we are a productivity platform for your app development. A virtual platform team.</p>
<h2 id="what-we-learned" tabindex="-1" class="marketing__blog_post__body__content__heading">
What we learned<a href="#what-we-learned" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What we learned"></a></h2>
<p>
Something we learned this year is that developer needs fall into two buckets: <em>problems teams actively seek solutions for</em>, and <em>problems they&#39;ve learned to live with</em>. The first category is straightforward—teams know what they need and can evaluate solutions easily. CI fits here. The second category is more interesting. Take build and test performance: teams often work without visibility into what&#39;s slowing them down. Many accept poor productivity as normal until it becomes unbearable. When we built insights, we weren&#39;t just offering a feature—we were helping teams see problems they didn&#39;t know they could solve. That&#39;s where we believe we can deliver the most value: illuminating the invisible friction that teams have normalized.</p>
<p>
When it comes to growth, our strategy continues to be the same: publish great content that goes deep into areas that interest our community, and share the vision we have for the space we build for. This doesn&#39;t bring customers directly, but creates the brand awareness that brings us closer to companies. We tried cold outreaches, but they&#39;re not effective. Developers don&#39;t like to be contacted through random channels. Developers don&#39;t like going through lengthy procurement, security, or legal processes. You can&#39;t sell to developers the way you&#39;d sell enterprise software. You have to <a href="https://www.heavybit.com/library/article/developer-marketing-mistakes">earn their trust</a> through substance, not spectacle.</p>
<p>
What works is engaging in conversations as early as people show up in our community. We try to understand what brought them there, and then we keep those conversations warm. We hold the hands of our prospects, and they appreciate having an engineering team sitting virtually next to them. GitLab calls this the <a href="https://handbook.gitlab.com/handbook/engineering/open-source/growth-strategy/"><em>&quot;open core flywheel&quot;</em></a>: community contributions fuel product innovation, which attracts more users, which generates more revenue, which enables more investment in the product. We&#39;re building our own version of this flywheel.</p>
<h2 id="gaining-traction" tabindex="-1" class="marketing__blog_post__body__content__heading">
Gaining traction<a href="#gaining-traction" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Gaining traction"></a></h2>
<p>
We closed the year with good sales momentum, and we believe we&#39;ll reach profitability in Q1 or Q2 next year. We can&#39;t emphasize enough how important this is. It signals there&#39;s a solid foundation here and a validation that Tuist is addressing the right needs.</p>
<p>
We&#39;ve closed deals that we wouldn&#39;t have imagined years ago. Hopefully we&#39;ll share more about those next year in the form of case studies, because the impact that Tuist has had in their ability to ship apps fast is astounding. Did we mention we are having first conversations with Korean companies where Tuist has traditionally had a huge presence through its communities? Localization and supporting the communities that form around open source is something we actively work on. It involves understanding the culture you&#39;re building for and adapting your solution to fit their expectations and needs.</p>
<h2 id="where-we-go-from-here" tabindex="-1" class="marketing__blog_post__body__content__heading">
Where we go from here<a href="#where-we-go-from-here" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Where we go from here"></a></h2>
<p>
We want to reach teams that are burning engineering resources on tooling problems. Teams where productivity has gotten so bad that leadership is considering abstracting the platform away entirely. We want to bring them joy again, the feeling of building apps without fighting an unreliable toolchain.</p>
<p>
We also noticed that Android teams essentially have one option when it comes to build optimization and insights. There&#39;s an opportunity there to simplify contracts and bring something fresh and better. In 2026, we&#39;re expanding to Android by integrating our features with Android build systems. All our solutions are valued in Android too, and we could simplify the vendor landscape for our customers by being their single productivity platform across ecosystems.</p>
<p>
This reminds us of the problem that had to be solved in global shipping. Before the 1950s, moving cargo between ships, trucks, and trains was a nightmare of incompatible systems and manual labor. Then <a href="https://en.wikipedia.org/wiki/Containerization">standardized shipping containers</a> came along, creating a universal interface regardless of what was being transported or who was transporting it. The result transformed global logistics. We see a similar opportunity in build infrastructure. Many build systems and test runners with similar capabilities but inconsistent contracts. We want to build the bridge that solves this fragmentation, the shipping container for developer toolchains.</p>
<p>
This doesn&#39;t mean we&#39;re building another build system. We&#39;re not interested in replacing Gradle or Xcode&#39;s build system. We&#39;re interested in the layer above them: the insights, the caching, the optimization. And we want to build that layer in the open. When you open-source the technology and offer to run it as a service, you become the natural choice. Would you pay Grafana for hosting a Grafana instance, or someone else? Likely Grafana, right? By contributing the technology back to the ecosystem, you earn the trust to run it. We see Tuist&#39;s role becoming two-fold: making ecosystems evolve through open source, and bridging the gap between build systems and infrastructure as a service. For example, while building our registry we found and fixed several bugs in SwiftPM&#39;s registry implementation (<a href="https://github.com/swiftlang/swift-package-manager/pull/8166">#8166</a>, <a href="https://github.com/swiftlang/swift-package-manager/pull/8188">#8188</a>, <a href="https://github.com/swiftlang/swift-package-manager/pull/8194">#8194</a>) and contributed performance improvements that <a href="https://github.com/swiftlang/swift-package-manager/pull/8203">parallelize package resolution</a>. The ecosystem gets better, and so do we.</p>
<p>
Another thing that became obvious throughout the year is that to enable new developer experiences, we need more control over where things run. Latency matters. If your cache is far from where you&#39;re developing, the experience suffers. Most solutions are optimized for CI, where you can co-locate cache servers and CI environments on the same network. But what about developers working remotely? What about agentic coding environments that also need fast builds, caching, and insights? These environments don&#39;t run in the same network where CI is hosted, resulting in higher latency and degraded experience.</p>
<p>
This CI-centric mindset has created solutions that disregard the diversity of environments we have today: local development, CI, and now agentic coding environments like <a href="https://claude.ai/code">Claude Code</a> and <a href="https://openai.com/index/introducing-codex/">Codex</a>. We want to build infrastructure that treats all these environments as first-class citizens. This is going to be our first step into deeper infrastructure, and we couldn&#39;t be more excited. We don&#39;t yet know the full shape it will take, but we&#39;re confident in the direction.</p>
<h2 id="looking-ahead" tabindex="-1" class="marketing__blog_post__body__content__heading">
Looking ahead<a href="#looking-ahead" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Looking ahead"></a></h2>
<p>
Our focus today remains strong on mobile. But next year&#39;s expansion to Android, hopefully with a good level of agnosticism, will give us a foundation to understand the <em>content</em>, not just the <em>containers</em>. For years, many have focused on the containers: <em>where</em> things run, whether that&#39;s local development, CI, or agentic environments. But the content, <em>what</em> actually runs inside them, has been largely ignored. With the right observability, that content can be optimized quite significantly.</p>
<p>
We&#39;re ready to jump into this space with a fresh take. One that is more open. One that places community first. One that values innovation over imposing restrictions to stay afloat. The best tools get out of your way and make you more productive. The best companies build trust through transparency and earn your business by genuinely solving your problems. That&#39;s what we&#39;re building.</p>
<h2 id="thank-you" tabindex="-1" class="marketing__blog_post__body__content__heading">
Thank you<a href="#thank-you" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Thank you"></a></h2>
<p>
None of this would be possible without the people who contribute to Tuist. Whether it&#39;s code, documentation, translations, bug reports, or community discussions, every contribution matters.</p>
<p>
First, the team. <a href="https://github.com/cschmatzler">Chris</a> joined and immediately made an impact, scaling our infrastructure, evolving our caching system to improve its latency and reliability, and implementing our design system for Phoenix LiveView. <a href="https://github.com/asmitbm">Asmit</a> brought design excellence to everything we do, from Noora to the marketing site to the countless details that make Tuist feel polished. <a href="https://github.com/fortmarek">Marek</a> has been the engine behind most of what we shipped this year, from the registry to test insights to countless improvements in the CLI.</p>
<p>
From the community, <a href="https://github.com/hiltonc">Hilton Campbell</a> stood out with over 15 merged PRs, including <a href="https://github.com/tuist/tuist/pull/8122">cache profiles</a>, <a href="https://github.com/tuist/tuist/pull/8561">Config manifest caching</a>, <a href="https://github.com/tuist/tuist/pull/6680">tag-based generation</a>, and a stream of bug fixes that made Tuist more reliable for everyone. <a href="https://github.com/danyf90">Daniele Formichelli</a> continued his long-standing contributions with 10 commits this year. <a href="https://github.com/simoncook">Simon Cook</a>, <a href="https://github.com/mulyarm">Mikhail</a>, and <a href="https://github.com/fdiaz">Francisco Diaz</a> each contributed multiple improvements. <a href="https://github.com/rofle100lvl">Gorbenko Roman</a>, <a href="https://github.com/paultaykalo">Paul Taykalo</a>, <a href="https://github.com/natanrolnik">Natan Rolnik</a>, <a href="https://github.com/waltflanagan">Mike Simons</a>, and <a href="https://github.com/imaginativeshohag">Md. Mahmudul Hasan Shohag</a> all made their mark with multiple contributions.</p>
<p>
We also received valuable contributions from <a href="https://github.com/yusufozgul">Yusuf Özgül</a>, <a href="https://github.com/devyhan93">YoHan Cho</a>, <a href="https://github.com/muukii">Hiroshi Kimura</a>, <a href="https://github.com/lukevanin">Luke Van In</a>, <a href="https://github.com/liamnichols">Liam Nichols</a>, <a href="https://github.com/kolos65">Kolos Foltányi</a>, <a href="https://github.com/DenTeleworzzz">Denys Telezhkin</a>, <a href="https://github.com/connor-ricks">Connor Ricks</a>, <a href="https://github.com/amarcadet">Antoine Marcadet</a>, <a href="https://github.com/FelixLisczyk">Felix Lisczyk</a>, <a href="https://github.com/stefanomondino">Stefano Mondino</a>, <a href="https://github.com/e1hanw0ng">Ethan Wong</a>, and many others who submitted fixes, improvements, and new features throughout the year.</p>
<p>
<a href="https://github.com/Ryu0118">Ryu0118</a> brought <a href="https://github.com/tuist/noora/pull/772">Sendable conformance to Noora</a>, helping us keep up with Swift&#39;s concurrency evolution. Noora also got sharper thanks to feedback from <a href="https://github.com/Joannis">Joannis Orlandos</a>, <a href="https://github.com/finnvoor">Finn Voorhees</a>, <a href="https://github.com/rmenezes">Raul Menezes</a>, and <a href="https://github.com/Ernest0-Production">Ernest0N</a>.</p>
<p>
Our Korean community continued to grow, with <a href="https://github.com/2sem">2sem</a> writing <a href="https://github.com/tuist/awesome-tuist/pull/25">blog posts</a> and reporting issues that helped us improve localization. <a href="https://github.com/jihoonahn">jihoonahn</a> added <a href="https://github.com/tuist/awesome-tuist/pull/18">TuistUI Plugin</a>, <a href="https://github.com/zhgchgli0718">ZhgChgLi</a> contributed <a href="https://github.com/tuist/awesome-tuist/pull/17">XCFolder</a>, and <a href="https://github.com/shahzadmajeed">shahzadmajeed</a> shared a <a href="https://github.com/tuist/awesome-tuist/pull/16">code signing plugin</a>. <a href="https://github.com/leogdion">Leo Dion</a> kept the <a href="https://github.com/tuist/awesome-tuist/pull/19">EmpowerApps resources</a> fresh, and <a href="https://github.com/iosdevzone">iosdevzone</a> caught <a href="https://github.com/tuist/tuist/pull/8979">broken links</a> before our users did.</p>
<p>
And then there are the translators. Sofia Kalinina, Boram Jeong, Randy Lu, Emirhan Karahan, and many others through <a href="https://translate.tuist.dev">translate.tuist.dev</a> made Tuist accessible to developers around the world. Thank you.</p>
<p>
We&#39;re bound to have missed some names, and we apologize for that. If you contributed in any way, know that we see you and appreciate you. Building something like Tuist is a team sport, and you&#39;re all part of the team.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ monday.com cut CI time in half ]]></title>
      
      
      <author>
        <name><![CDATA[ monday.com ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ monday.com slashed CI times from 20 to 9 minutes and scaled to 200 modules with Tuist. Learn how their 20-engineer iOS team transformed their development workflow. ]]></summary>
      <link href="https://tuist.dev/customers/monday"/>
      <id>https://tuist.dev/customers/monday</id>
      <updated>Mon, 15 Dec 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <h2 id="the-challenge" tabindex="-1" class="marketing__blog_post__body__content__heading">
The challenge<a href="#the-challenge" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The challenge"></a></h2>
<p>
At <a href="https://monday.com">monday.com</a>, we work with a large, mixed iOS codebase that has been evolving for nearly a decade. Dozens of engineers contribute hundreds of commits every month across multiple product areas. What began as a small team eventually grew to almost 20 iOS engineers, and with that growth came real architectural and workflow challenges.</p>
<p>
Building the project was slow and messy. We wanted a highly modular setup that allowed developers to build only what they needed, as quickly as possible. But creating modules inside Xcode was painful and error-prone, and the project naturally drifted toward a big monolithic structure. Code became tightly coupled, merge conflicts were common, and restructuring the project often felt like fighting the tool instead of building with it.</p>
<blockquote>
  <p>
&quot;Restructuring the project often felt like fighting the tool instead of building with it.&quot;  </p>
</blockquote>
<p>
The underlying Xcode project format also caused hidden configuration issues. Because everything lived in pseudo-XML, it was easy to end up with unexpected behaviors, inconsistent settings, or modules that behaved differently for reasons no one could easily trace. Understanding why something was configured in a certain way was becoming harder over time. We needed a cleaner, more reliable, and more scalable way to define the project.</p>
<h2 id="choosing-tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Choosing Tuist<a href="#choosing-tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Choosing Tuist"></a></h2>
<p>
Both <a href="https://www.linkedin.com/in/natanrolnik/">Natan</a> and <a href="https://www.linkedin.com/in/shaimishali/">Shai</a> had followed Tuist for years and were already fans of the team and their open source work. Each of us had contributed to Tuist in the past, and Natan had even served on the <a href="https://github.com/tuist/tuist?tab=readme-ov-file#core-alumni">core team</a>, so we knew the project well enough to trust its design, direction, and philosophy. On top of that, Natan and our colleague JD had used Tuist successfully at their previous company, which gave us additional confidence.</p>
<p>
We also had the chance to meet Pedro and Marek at a few conferences and left those conversations with a strong sense of trust in both the people and the product. Seeing other large companies use Tuist to solve similar challenges reinforced that we were on the right path. For a rapidly growing project with a massive line count, Tuist felt like the right tool to help us transition from a large monolith to a more modular, scalable, and maintainable architecture.</p>
<h2 id="the-approach" tabindex="-1" class="marketing__blog_post__body__content__heading">
The approach<a href="#the-approach" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The approach"></a></h2>
<p>
In mid-2022, Natan and JD kicked off a full migration of our Xcode project to Tuist <a href="https://docs.tuist.dev/en/guides/features/projects">generated projects</a>. They began with the leaf nodes, the ones with the fewest dependencies, and gradually worked their way up the dependency hierarchy. The initial pull request was massive, with more than 60,000 changes. Tools like <a href="https://github.com/bloomberg/xcdiff">xcdiff</a> helped us validate that everything remained consistent throughout the process.</p>
<p>
That first migration got the entire team working with Tuist. Over time, we built many of our own abstractions on top of it, including unified Framework and <a href="https://docs.tuist.dev/en/guides/features/projects/code-sharing">Project Description Helpers</a> that allow anyone on the team to create new modules quickly and safely, as well as custom <a href="https://docs.tuist.dev/en/guides/features/projects/synthesized-files">Resource Synthesizers</a> for Lottie animations and other specialized resources. Every module also includes its own Preview App, Tests, etc, which lets developers work in complete isolation instead of building the entire application. This was a significant improvement in quality of life and developer experience.</p>
<p>
A bit later, we adopted Tuist’s <a href="https://docs.tuist.dev/en/guides/features/cache">module cache</a>. This made a noticeable difference in build times, especially in CI. Today, tuist generate has become a familiar command across the team and a natural part of our daily workflow.</p>
<h2 id="the-results" tabindex="-1" class="marketing__blog_post__body__content__heading">
The results<a href="#the-results" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The results"></a></h2>
<ul>
  <li>
All modules, app targets, and configurations are now defined in Tuist’s Swift-based manifests. It provides a  real source of truth, far more transparent and reliable than managing settings inside a pbxproj file.  </li>
  <li>
We now maintain around 200 modules, and creating new ones is simple enough that anyone on the team feels comfortable doing it. The cost of modularizing has gone way down.  </li>
  <li>
Our CI merge workflow dropped from more than 20 minutes in 2022 to about 9 minutes today. This came from many improvements across the board, but Tuist&#39;s <a href="https://docs.tuist.dev/en/guides/features/cache">module cache</a> played a significant role. The result is a faster iteration cycle and a meaningful reduction in developer hours lost to waiting on builds.  </li>
  <li>
It&#39;s also much easier to make large-scale changes or experiment with a new build configuration. Because everything is defined in code, large refactors and optimizations feel safer, more predictable, and far more approachable.  </li>
</ul>
<blockquote>
  <p>
&quot;We now maintain around 200 modules, and creating new ones is simple enough that anyone on the team feels comfortable doing it.&quot;  </p>
</blockquote>
<h2 id="what’s-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next<a href="#what’s-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next"></a></h2>
<p>
Tuist gives us confidence that we can continue scaling the team and the codebase. Spinning up a new app is basically as simple as creating a new target and reusing the modules we already have, which opens the door for faster experimentation across the engineering team.</p>
<p>
We&#39;re excited to keep improving the developer experience for our iOS engineers, and we&#39;re equally excited to see what the Tuist team builds next. Their work has already had a significant impact on how we ship software, and we expect that impact to continue as we grow.</p>
<blockquote>
  <p>
&quot;Tuist gives us confidence that we can continue scaling the team and the codebase.&quot;  </p>
</blockquote>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Test Insights for Xcode ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Get Xcode test analytics and optimize your test suite with Tuist Test Insights. ]]></summary>
      <link href="https://tuist.dev/blog/2025/12/03/test-insights"/>
      <id>https://tuist.dev/blog/2025/12/03/test-insights</id>
      <updated>Wed, 03 Dec 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Earlier this year, we announced <a href="/blog/2025/06/05/build-insights">Build Insights</a> – the best way to understand your Xcode builds in local and CI environments. But teams were still kept in the dark about their tests. Tuist Test Insights adds Xcode test analytics to fill that gap.</p>
<p>
As your test suite grows, you will inevitably face pains like slow test suites or flaky tests. Additionally, debugging issues on the CI has always been a challenge – can&#39;t I get a link that tells me exactly what went wrong, instead of trying to understand the logs, running the tests locally, or downloading the <code class="inline">.xcresult</code>?</p>
<p>
Test Insights gives you a comprehensive overview of your overall test suite <em>over time</em> along with a detailed report of every test run to ensure your test suite is healthy and is not slowing down your development. No one wants to be waiting an eternity for a CI pipeline to finish only for it to fail with a cryptic error message.</p>
<p>
👉 If you&#39;d like to see it in action, check out the video below:</p>
<iframe title="Test Insights" width="560" height="315" src="https://videos.tuist.dev/videos/embed/29g22xYLk6Wjz1q5AHYKXC" style="border: 0px;" allow="fullscreen" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="getting-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting started<a href="#getting-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting started"></a></h2>
<p>
To get started with test insights, you will need a <a href="https://docs.tuist.dev/en/server/introduction/accounts-and-projects">Tuist account and a project</a>. The best way to get started is to use our <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist">CLI</a> and run the <code class="inline">tuist init</code> command.</p>
<p>
Once you authenticate, you will need to add a <code class="inline">tuist inspect test</code> command in your Xcode scheme test post-action – unless you use <a href="https://docs.tuist.dev/en/guides/develop/projects">generated projects</a>, in which case we generate the post-action for you. Note that the exact script depends on your installation. If you use <a href="https://mise.jdx.dev/">mise</a>, the full script should be:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
$HOME/.local/bin/mise x -C $SRCROOT -- tuist inspect test    </shiki-highlight>
  </div>
</div>
<p>
  <img src="/marketing/images/blog/2025/12/03/test-insights/inspect-test-scheme-post-action.png" alt="Screenshot of how to set up an Xcode post action for test insights">
</p>
<p>
For more details how to set up test insights, head over to our <a href="https://docs.tuist.dev/en/guides/develop/insights">docs</a>.</p>
<h2 id="test-detail" tabindex="-1" class="marketing__blog_post__body__content__heading">
Test detail<a href="#test-detail" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Test detail"></a></h2>
<p>
Once you start tracking tests both on the CI and in your local environments, things start to get interesting. Let&#39;s imagine the following scenario:</p>
<ul>
  <li>
your test fails  </li>
  <li>
you look into your CI logs, but the <code class="inline">xcodebuild</code> log doesn&#39;t include the exact test failure, only which test failed  </li>
  <li>
you try to reproduce locally, but the test passes  </li>
  <li>
you need to update your CI pipeline to upload the <code class="inline">.xcresult</code> and re-run the test  </li>
  <li>
the test may (or may not) fail again – in case, it does, you can finally download the <code class="inline">.xcresult</code> and investigate the failure in Xcode  </li>
</ul>
<p>
So. Much. Friction. Wouldn&#39;t it be awesome if you would get a link to your failed test directly in the PR or in your CI logs? That&#39;s exactly what you&#39;ll get with test insights:</p>
<p>
  <img src="/marketing/images/blog/2025/12/03/test-insights/test-detail.png" alt="Screenshot of a failed test detail">
</p>
<p>
Let&#39;s imagine another scenario: your run on the CI was taking longer than expected. But you have no idea why. With test insights, you can now get a breakdown of how long individual test cases, suites, and modules took to run. And you can compare them with the average.</p>
<p>
  <img src="/marketing/images/blog/2025/12/03/test-insights/test-breakdown.png" alt="Screenshot of a test breakdown">
</p>
<h2 id="tests-over-time" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tests over time<a href="#tests-over-time" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tests over time"></a></h2>
<p>
Things start to get really interesting when you start tracking tests over time. Is your test suite slow? We can tell you which of your test cases are the slowest, so you know what to focus on:</p>
<p>
  <img src="/marketing/images/blog/2025/12/03/test-insights/slowest-test-cases.png" alt="List of the slowest test cases">
</p>
<p>
Is your test suite getting faster or slower? Has there been a recent regression in the test execution time? The Tuist dashboard provides you with answers to these questions as well:</p>
<p>
  <img src="/marketing/images/blog/2025/12/03/test-insights/test-execution-time.png" alt="Graph of test execution time">
</p>
<p>
And it bears repeating – the test insights are environment-agnostic, so you can get a holistic view of your test suite&#39;s performance across different environments, not just your CI. Additionally, the test insights are CI-agnostic, it doesn&#39;t matter which CI provider you&#39;re using, you will get the same insights wherever you run your tests.</p>
<blockquote>
  <p>
Do you want to explore the feature on your own? Our Tuist <a href="https://tuist.dev/tuist/tuist/tests">dashboard is open for anyone</a>, including the new test insights.  </p>
</blockquote>
<h2 id="how-test-insights-work" tabindex="-1" class="marketing__blog_post__body__content__heading">
How test insights work<a href="#how-test-insights-work" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How test insights work"></a></h2>
<p>
You might be wondering what happens under the hood when you run <code class="inline">tuist inspect test</code>. Here&#39;s a quick overview:</p>
<ol>
  <li>
The post-action finds the latest <code class="inline">.xcresult</code> from your derived data. The derived data location is determined based on the <code class="inline">$SRCROOT</code> environment variable that Xcode provides.  </li>
  <li>
We use Apple&#39;s <code class="inline">xcresulttool</code> to get the JSON representation of the <code class="inline">.xcresult</code>. This gives us access to the structured test data that Xcode collects.  </li>
  <li>
We extract the most important pieces – duration, test status, failure messages, and more – and send the data to the Tuist server.  </li>
  <li>
All of this happens in the background, so Xcode can finish the test action without waiting for the upload to complete.  </li>
  <li>
The server stores the data in <a href="https://clickhouse.com/">ClickHouse</a>, an analytics database optimized for fast queries over large datasets. This allows us to efficiently analyze your test history and surface insights in the dashboard.  </li>
</ol>
<p>
Since the full implementation is open-source, you can check it out <a href="https://github.com/tuist/tuist/blob/22b22cadd2631efcc73dde6d0881032a86947493/cli/Sources/TuistXCResultService/XCResultService.swift">here</a>.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
Test Insights takes Xcode&#39;s test data, makes it readily available in your browser, and analyzes it over time – whether you need to debug a failing test on CI or understand how your test suite&#39;s performance is trending.</p>
<p>
But this is just the beginning. The test insights will provide us with a great foundation to provide more capable features in the future. We want to be more proactive and leverage the data we track to either optimize your projects or tell you what&#39;s wrong – without you having to do the digging. Here are some of the things we will be working on:</p>
<ul>
  <li>
Test flakiness: which of my tests are flaky? Can you skip running them until the flakiness is resolved?  </li>
  <li>
Sharding: For optimal sharding, it&#39;s important for each shard to run for a similar amount of time. We already know how long your tests take on average, so we can use that information to optimize your sharding strategy.  </li>
  <li>
Slow test alerts: have you added a test that is abnormally slow? Let us tell you!  </li>
  <li>
Snapshot attachments: if you&#39;re using snapshot testing, we&#39;ll show you the image differences directly in the test detail  </li>
</ul>
<p>
Are there any day-to-day pains related to your test suite? Let us know and we&#39;d love to prioritize solving your needs.</p>
<p>
To learn more about test insights, head over to our <a href="https://docs.tuist.dev/en/guides/features/insights#tests">documentation</a>. If you have any feedback or suggestions, please don&#39;t hesitate to reach out to us at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Teaching AI to Read Xcode Builds ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ From debugging build issues to building agent-friendly build observability. Exploring how structured build data could transform how AI agents understand and optimize Xcode builds. ]]></summary>
      <link href="https://tuist.dev/blog/2025/11/27/teaching-ai-to-read-xcode-builds"/>
      <id>https://tuist.dev/blog/2025/11/27/teaching-ai-to-read-xcode-builds</id>
      <updated>Thu, 27 Nov 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When an Xcode build fails, developers instinctively reach for logs. We scroll through walls of text, searching for that one cryptic linker error or mysterious crash buried in the noise. The build system knows exactly what happened (every compilation, every dependency resolution, every timing metric) but it speaks a language optimized for machines, not humans. And certainly not for AI agents.</p>
<p>
What if we could change that? What if AI agents could actually understand builds, not just parse their text output?</p>
<blockquote>
  <p>
This is an exploration of what could be possible. Some of the concepts discussed are aspirational and would require Apple&#39;s support to fully realize.  </p>
</blockquote>
<h2 id="the-problem:-build-logs-are-not-built-for-understanding" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Problem: Build Logs Are Not Built for Understanding<a href="#the-problem:-build-logs-are-not-built-for-understanding" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Problem: Build Logs Are Not Built for Understanding"></a></h2>
<p>
Picture this: you&#39;re building a large iOS app and hit a linker error. The output looks something like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
ld: warning: ignoring duplicate libraries: &#39;-lz&#39;
ld: Undefined symbols:
  _OBJC_CLASS_$_SomeFramework, referenced from:
      objc-class-ref in MyTarget.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)    </shiki-highlight>
  </div>
</div>
<p>
What do you do next? You scroll up through hundreds of lines of compilation output, grep for &quot;error&quot;, check if your Swift Package dependencies resolved correctly, maybe clean the build folder, and try again. If that doesn&#39;t work, you might delete the DerivedData folder entirely and rebuild from scratch. Sometimes that fixes things. Sometimes it doesn&#39;t, and you&#39;re left wondering what actually went wrong.</p>
<p>
The frustrating part is that the build system knows exactly what happened. It knows which target failed, which dependency was missing, what the entire dependency graph looks like, and how long each step took. But instead of exposing this rich structured data, it communicates through a stream of text that looks like it was designed for a terminal from the 1980s.</p>
<p>
We&#39;ve all been there. We&#39;ve all lost hours to build failures that should have taken minutes to diagnose.</p>
<h3 id="what-xcodebuild-actually-gives-you" tabindex="-1" class="marketing__blog_post__body__content__heading">
What xcodebuild actually gives you<a href="#what-xcodebuild-actually-gives-you" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What xcodebuild actually gives you"></a></h3>
<p>
When you run <code class="inline">xcodebuild</code> from the command line, you get output that mixes progress indicators, compiler invocations, warnings, and errors into a single undifferentiated stream:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
CompileSwift normal arm64 /path/to/File1.swift
CompileSwift normal arm64 /path/to/File2.swift
CompileSwift normal arm64 /path/to/File3.swift
...hundreds more lines...
/path/to/File47.swift:23:15: error: cannot find &#39;SomeType&#39; in scope    </shiki-highlight>
  </div>
</div>
<p>
This output wasn&#39;t designed for debugging. It was designed for logging. There&#39;s no structure, no hierarchy, no way to programmatically distinguish between a compilation step and a linker invocation without parsing the text itself.</p>
<p>
For humans, tools like <a href="https://github.com/cpisciotta/xcbeautify">xcbeautify</a> help by colorizing the output and filtering out noise. They make the wall of text easier to scan. But these tools are designed for human eyes scanning a terminal. They take unstructured text and make it prettier unstructured text.</p>
<h3 id="why-this-matters-for-ai-agents" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why this matters for AI agents<a href="#why-this-matters-for-ai-agents" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why this matters for AI agents"></a></h3>
<p>
Now consider what happens when an AI agent tries to help you debug a build failure. The agent faces a fundamental challenge: the output it receives is unstructured text. It has to parse free-form strings, try to guess at relationships between different lines, and hope that the error message contains enough context to be useful.</p>
<p>
Even with perfect parsing (which is hard, because the output format isn&#39;t formally specified and can change between Xcode versions), there&#39;s critical information that simply isn&#39;t present in the logs. None of this information appears in <code class="inline">xcodebuild</code> output. It exists inside the build system, but it doesn&#39;t make it to the terminal.</p>
<h3 id="a-step-in-the-right-direction:-xcsift" tabindex="-1" class="marketing__blog_post__body__content__heading">
A step in the right direction: xcsift<a href="#a-step-in-the-right-direction:-xcsift" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A step in the right direction: xcsift"></a></h3>
<p>
There&#39;s an interesting project called <a href="https://github.com/ldomaradzki/xcsift">xcsift</a> that takes a different approach to this problem. Instead of formatting build output for humans to read, it transforms <code class="inline">xcodebuild</code> output into structured JSON that&#39;s optimized for AI consumption:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
xcodebuild build 2&gt;&amp;1 | xcsift --format json    </shiki-highlight>
  </div>
</div>
<p>
This produces machine-readable output with extracted errors, warnings, and test failures organized into a proper data structure. The tool even offers a custom format called &quot;TOON&quot; that reduces token usage by 30-60% compared to JSON, which matters when you&#39;re paying per token for AI API calls.</p>
<p>
This is a genuinely clever solution. It works within the constraints of what <code class="inline">xcodebuild</code> exposes and makes the best of a difficult situation.</p>
<p>
But there&#39;s a fundamental limitation: <code class="inline">xcodebuild</code> output is a flattened representation of what&#39;s actually happening. The build system internally maintains a rich graph of dependencies (target A depends on target B, file X imports module Y, this compilation must wait for that linking step). When it writes to stdout, all of that structure gets serialized into a linear stream of text. The graph becomes a list. The relationships disappear.</p>
<p>
xcsift can parse that list beautifully, but it can&#39;t reconstruct the graph. It can tell you that target A failed, but not that targets B, C, and D were waiting on A and never got a chance to run. It can tell you that a file was compiled, but not why it needed recompilation or what downstream tasks were triggered as a result.</p>
<p>
The build system has this information. It just doesn&#39;t share it.</p>
<h3 id="the-gap-between-parsing-logs-and-observing-builds" tabindex="-1" class="marketing__blog_post__body__content__heading">
The gap between parsing logs and observing builds<a href="#the-gap-between-parsing-logs-and-observing-builds" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The gap between parsing logs and observing builds"></a></h3>
<p>
There&#39;s a meaningful difference between parsing build logs and actually observing what the build system is doing. It&#39;s a bit like the difference between reading a transcript of a meeting and actually being in the room. The transcript captures the words that were spoken, but it loses the timing, the context, the reactions, the side conversations.</p>
<p>
When you parse <code class="inline">xcodebuild</code> output, you&#39;re working with what the build system chose to print. When you observe the build system&#39;s internal messages, you see everything: every task that started and ended, every dependency that was resolved, every timing measurement, every decision the scheduler made.</p>
<p>
That&#39;s what we wanted to explore. What if instead of parsing the output of <code class="inline">xcodebuild</code>, we could tap into the structured messages that the build system uses internally to coordinate its work? What would that unlock for AI agents trying to understand and debug builds?</p>
<h2 id="discovering-what-builds-actually-know" tabindex="-1" class="marketing__blog_post__body__content__heading">
Discovering What Builds Actually Know<a href="#discovering-what-builds-actually-know" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Discovering What Builds Actually Know"></a></h2>
<p>
A few months ago, we got curious. We built a small tool called <a href="https://github.com/tuist/XCBLoggingBuildService">XCBLoggingBuildService</a> to intercept the communication between Xcode and its build service. We wanted to see what was actually happening under the hood.</p>
<p>
What we found changed how we think about build observability.</p>
<p>
When you hit &quot;Build&quot; in Xcode or run <code class="inline">xcodebuild</code>, you&#39;re not directly invoking compilers and linkers. Your request goes to a separate process called SWBBuildService. This is the actual build engine. Xcode is just a frontend that sends requests, receives responses, and translates them into the UI you see. The same goes for <code class="inline">xcodebuild</code>, which translates them into text.</p>
<p>
The communication between these processes isn&#39;t text. It&#39;s not JSON either. It&#39;s <a href="https://msgpack.org/">MessagePack</a>, a binary serialization format, flowing over stdin/stdout pipes. And here&#39;s the thing: every build event is a discrete, typed message with structured data.</p>
<p>
Apple recently open-sourced this build system as <a href="https://github.com/swiftlang/swift-build">swift-build</a>. So now we can actually read the message definitions. We can see exactly what data flows between components. What was once a black box is now source code anyone can study.</p>
<h3 id="the-difference-is-striking" tabindex="-1" class="marketing__blog_post__body__content__heading">
The difference is striking<a href="#the-difference-is-striking" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The difference is striking"></a></h3>
<p>
Let&#39;s look at a concrete example. When you compile a Swift file, <code class="inline">xcodebuild</code> prints this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
CompileSwift normal arm64 /path/to/MyFile.swift    </shiki-highlight>
  </div>
</div>
<p>
One line. That&#39;s it.</p>
<p>
But internally, the build service sends a <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBProtocol/BuildOperationMessages.swift#L420"><code class="inline">BuildOperationTaskStarted</code></a> message that looks like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
BuildOperationTaskStarted:
  id: unique task identifier
  targetID: which target this belongs to
  parentID: the parent task (if nested)
  info:
    taskName: &quot;CompileSwift&quot;
    executionDescription: &quot;Compiling MyFile.swift&quot;
    interestingPath: &quot;/path/to/MyFile.swift&quot;
    signature: content-addressable hash for caching    </shiki-highlight>
  </div>
</div>
<p>
And when that compilation finishes, there&#39;s a <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBProtocol/BuildOperationMessages.swift#L445"><code class="inline">BuildOperationTaskEnded</code></a> message:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
BuildOperationTaskEnded:
  id: same task identifier
  status: succeeded | failed | cancelled
  metrics:
    utime: 1234567      # CPU time in user mode (microseconds)
    stime: 234567       # CPU time in kernel mode (microseconds)
    maxRSS: 104857600   # Peak memory usage (bytes)
    wcDuration: 2500000 # Wall clock duration (microseconds)    </shiki-highlight>
  </div>
</div>
<p>
See the difference? The protocol knows how long the compilation took, how much memory it used, which target it belonged to, and whether it was part of a larger task. It has a unique identifier that lets you correlate this task with any errors it produced, any output it generated, and its position in the dependency graph.</p>
<p>
None of that makes it to the terminal.</p>
<h3 id="what-gets-lost-in-translation" tabindex="-1" class="marketing__blog_post__body__content__heading">
What gets lost in translation<a href="#what-gets-lost-in-translation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What gets lost in translation"></a></h3>
<p>
When we started looking at the <a href="https://github.com/swiftlang/swift-build/tree/main/Sources/SWBProtocol">SWBProtocol</a> module, we kept finding data that never reaches <code class="inline">xcodebuild</code> output:</p>
<p>
Timing, for one. Not just &quot;the build took 45 seconds,&quot; but exactly how long each individual task took. You can see that a compilation ate 8 seconds of wall time but only 2 seconds of CPU time, which tells you it was probably blocked waiting for something else.</p>
<p>
Memory usage per task. If your CI builds are getting killed by the OOM killer, you could pinpoint exactly which compilation is the culprit.</p>
<p>
Task relationships. Every task knows which target it belongs to, and optionally which parent task spawned it. You can reconstruct the full tree of what happened, not just a flat list.</p>
<p>
Cache information. There&#39;s a message called <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBProtocol/BuildOperationMessages.swift#L385"><code class="inline">BuildOperationTaskUpToDate</code></a> that fires when a task was skipped because nothing changed. You could calculate your actual cache hit rate instead of guessing.</p>
<p>
And diagnostics. Errors don&#39;t come as text strings. They come as <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBProtocol/BuildOperationMessages.swift#L670"><code class="inline">BuildOperationDiagnosticEmitted</code></a> messages with the file path, line and column, source ranges, fix-it suggestions, and which component emitted them.</p>
<p>
The build system knows all of this. It&#39;s just not telling us.</p>
<h2 id="what-structured-build-data-unlocks" tabindex="-1" class="marketing__blog_post__body__content__heading">
What Structured Build Data Unlocks<a href="#what-structured-build-data-unlocks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What Structured Build Data Unlocks"></a></h2>
<p>
So we have this rich stream of structured messages flowing through the build system. What could we actually do with it if we captured and exposed it properly?</p>
<h3 id="intelligent-failure-diagnosis" tabindex="-1" class="marketing__blog_post__body__content__heading">
Intelligent failure diagnosis<a href="#intelligent-failure-diagnosis" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Intelligent failure diagnosis"></a></h3>
<p>
When a build fails today, an AI agent sees an error message and tries to help based on pattern matching against its training data. Sometimes that works. Often it doesn&#39;t, because the agent lacks context about your specific project.</p>
<p>
With structured build data, the agent could answer questions like:</p>
<ul>
  <li>
&quot;This linker error happened because target <code class="inline">NetworkKit</code> failed to build. <code class="inline">NetworkKit</code> depends on <code class="inline">CoreUtilities</code>, which succeeded, so the problem is isolated to <code class="inline">NetworkKit</code> itself.&quot;  </li>
  <li>
&quot;You&#39;ve seen this exact error three times in the last week. The first two times, cleaning the build folder fixed it. The third time, you had to delete DerivedData.&quot;  </li>
  <li>
&quot;This compilation failed at 2:34 PM. The last successful build was at 2:12 PM. Between those builds, you modified <code class="inline">APIClient.swift</code> and <code class="inline">Models/User.swift</code>.&quot;  </li>
</ul>
<p>
The agent isn&#39;t guessing anymore. It&#39;s working with actual build history and dependency information.</p>
<h3 id="performance-analysis-that-goes-beyond-timing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Performance analysis that goes beyond timing<a href="#performance-analysis-that-goes-beyond-timing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Performance analysis that goes beyond timing"></a></h3>
<p>
Build performance is usually measured in one number: how long did it take? But that number hides a lot of complexity. A 60-second build might be 60 seconds because you have one massive target that can&#39;t parallelize, or because you have 30 small targets with a long critical path, or because your incremental build isn&#39;t actually incremental.</p>
<p>
With task-level timing and dependency data, you can answer the questions that actually matter:</p>
<ul>
  <li>
&quot;Your build took 47 seconds, but only 12 seconds of that was actual compilation. The rest was waiting for code signing and asset catalog processing, which ran sequentially after everything else.&quot;  </li>
  <li>
&quot;The critical path runs through <code class="inline">FeatureA</code> → <code class="inline">SharedUI</code> → <code class="inline">MainApp</code>. If you could shave 5 seconds off <code class="inline">SharedUI</code>, your entire build would be 5 seconds faster.&quot;  </li>
  <li>
&quot;You have 8 CPU cores, but your build only achieved 3.2x parallelization. Here are the targets that are blocking better parallelization.&quot;  </li>
  <li>
&quot;This &#39;incremental&#39; build recompiled 847 files. Based on the task signatures, the trigger was a change to <code class="inline">Constants.swift</code>, which is imported by everything.&quot;  </li>
</ul>
<p>
The data includes start and end times for every task, plus which target each task belongs to. From this, you can compute concurrency over time, identify sequential chains (likely dependencies), find the critical path, and spot contention points where one target blocks many others.</p>
<p>
For example, if tasks from target A consistently end right before tasks from targets B, C, and D begin, target A is probably a dependency of all three. If A takes 20 seconds and blocks everything else, that&#39;s your bottleneck. The protocol also includes a <code class="inline">DependencyGraphResponse</code> message with an explicit adjacency list of target dependencies, so you can get the actual dependency graph, not just inferred relationships from timing.</p>
<p>
This is the kind of analysis that build engineers at large companies do manually, staring at build traces and dependency graphs. There&#39;s no reason an AI agent couldn&#39;t do it automatically if it had access to the same data.</p>
<h3 id="proactive-suggestions" tabindex="-1" class="marketing__blog_post__body__content__heading">
Proactive suggestions<a href="#proactive-suggestions" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Proactive suggestions"></a></h3>
<p>
Once you have historical build data, patterns start to emerge. An agent with access to weeks or months of build history could notice things like:</p>
<ul>
  <li>
&quot;Your clean build times have increased by 40% over the last month. The growth correlates with the addition of 12 new Swift files in the <code class="inline">Analytics</code> module.&quot;  </li>
  <li>
&quot;Builds on Monday mornings are consistently 2x slower than other times. This might be related to cache invalidation over the weekend.&quot;  </li>
  <li>
&quot;Developer A&#39;s builds fail 3x more often than Developer B&#39;s, and the failures are almost always linker errors. This might indicate an environment configuration issue.&quot;  </li>
  <li>
&quot;This target has been rebuilt from scratch in 80% of incremental builds. The problem appears to be a bridging header that changes frequently.&quot;  </li>
</ul>
<p>
None of this is possible with a single build&#39;s text output. It requires structured data that can be stored, queried, and compared over time.</p>
<h3 id="natural-language-queries-about-builds" tabindex="-1" class="marketing__blog_post__body__content__heading">
Natural language queries about builds<a href="#natural-language-queries-about-builds" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Natural language queries about builds"></a></h3>
<p>
Perhaps the most immediately useful application is simply being able to ask questions about your builds in plain English:</p>
<ul>
  <li>
&quot;What was the slowest target in my last build?&quot;  </li>
  <li>
&quot;How many warnings did we have last week compared to this week?&quot;  </li>
  <li>
&quot;Which files take the longest to compile?&quot;  </li>
  <li>
&quot;Has this test target always been this slow, or did something change recently?&quot;  </li>
  <li>
&quot;What percentage of my builds are clean builds versus incremental?&quot;  </li>
</ul>
<p>
These questions have answers. The build system knows the answers. We just don&#39;t have a good way to ask.</p>
<h3 id="why-this-matters-now" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why this matters now<a href="#why-this-matters-now" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why this matters now"></a></h3>
<p>
AI agents are becoming legitimate development tools. People use them to write code, debug issues, refactor systems, and automate workflows. But when it comes to builds, agents are working blind. They can see the code, but they can&#39;t see how the code gets built.</p>
<p>
As projects get larger and build systems get more complex, this gap becomes more painful. A developer might spend hours debugging a build issue that an agent could diagnose in seconds, if only the agent had access to the right data.</p>
<p>
The structured messages are already there. The build system already generates them. The question is whether we can capture them in a way that makes them accessible to the tools developers are increasingly relying on.</p>
<h2 id="inside-the-build-protocol" tabindex="-1" class="marketing__blog_post__body__content__heading">
Inside the Build Protocol<a href="#inside-the-build-protocol" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Inside the Build Protocol"></a></h2>
<p>
So where does this build service actually live? If you dig into your Xcode installation, you&#39;ll find it here:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
/Applications/Xcode.app/Contents/SharedFrameworks/XCBuild.framework/
  Versions/A/PlugIns/XCBBuildService.bundle    </shiki-highlight>
  </div>
</div>
<p>
That&#39;s the binary that does all the work. When you build something, Xcode spawns this as a separate process and talks to it over stdin/stdout pipes. Looking at <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBBuildService/BuildServiceEntryPoint.swift">BuildServiceEntryPoint.swift</a> in swift-build, you can see it also supports running in-process, which is probably how Xcode uses it for tighter integration.</p>
<h3 id="how-xcode-understands-your-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
How Xcode understands your project<a href="#how-xcode-understands-your-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How Xcode understands your project"></a></h3>
<p>
Before a build can start, the build service needs to understand your project structure. This happens through something called PIF: the Project Interchange Format.</p>
<p>
If you&#39;ve ever tried to parse an <code class="inline">.xcodeproj</code> file programmatically, you know it&#39;s a nightmare. The <code class="inline">.pbxproj</code> format is byzantine, poorly documented, and full of UUIDs that reference each other in ways that are hard to follow. PIF is what the build system actually uses internally, and it&#39;s much cleaner.</p>
<p>
Looking at the <a href="https://github.com/swiftlang/swift-build/tree/main/Sources/SWBCore/ProjectModel">ProjectModel</a> directory in swift-build, you can see the hierarchy: workspaces contain projects, projects contain targets, targets contain build phases, and build phases contain files. It&#39;s all defined in straightforward Swift structs like <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBCore/ProjectModel/Workspace.swift"><code class="inline">Workspace.swift</code></a>, <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBCore/ProjectModel/Project.swift"><code class="inline">Project.swift</code></a>, and <a href="https://github.com/swiftlang/swift-build/blob/main/Sources/SWBCore/ProjectModel/Target.swift"><code class="inline">Target.swift</code></a>.</p>
<p>
What&#39;s clever is that PIF supports incremental updates. The build service caches your project structure, and on subsequent builds, only the parts that changed get re-transferred. That&#39;s part of why incremental builds in Xcode feel faster than running <code class="inline">xcodebuild</code> from scratch each time.</p>
<h3 id="what-happens-during-a-build" tabindex="-1" class="marketing__blog_post__body__content__heading">
What happens during a build<a href="#what-happens-during-a-build" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What happens during a build"></a></h3>
<p>
When you actually kick off a build, there&#39;s a conversation that happens between Xcode and the build service. First, Xcode establishes a session. Then it transfers the project structure (or updates to it). Then it sends a build request with the configuration, scheme, and targets.</p>
<p>
During execution, the messages we talked about earlier start flowing: targets starting and ending, tasks starting and ending, progress updates, diagnostics. When everything&#39;s done, there&#39;s a final message with the overall status and aggregate metrics.</p>
<p>
The interesting thing is that sessions can be reused. Xcode doesn&#39;t tear down the connection after each build. It keeps the session alive so that subsequent builds can skip the setup phase and benefit from cached state.</p>
<h3 id="you-can-swap-out-the-build-service" tabindex="-1" class="marketing__blog_post__body__content__heading">
You can swap out the build service<a href="#you-can-swap-out-the-build-service" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to You can swap out the build service"></a></h3>
<p>
Here&#39;s what makes this really interesting for observability: Xcode explicitly supports using a custom build service.</p>
<p>
There&#39;s an environment variable called <code class="inline">XCBBUILDSERVICE_PATH</code>. If you set it, Xcode will use whatever binary you point to instead of the bundled one. The swift-build repository even includes a <a href="https://github.com/swiftlang/swift-build/blob/main/Plugins/launch-xcode/launch-xcode.swift">launch-xcode plugin</a> that builds swift-build from source and launches Xcode with the custom service:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
swift package --disable-sandbox launch-xcode    </shiki-highlight>
  </div>
</div>
<p>
This means you could modify the build service, add logging for the messages you care about, rebuild it, and have Xcode use your version. Or you could build a proxy that sits between Xcode and the real build service, capturing messages as they flow through.</p>
<p>
That&#39;s exactly what <a href="https://github.com/tuist/XCBLoggingBuildService">XCBLoggingBuildService</a> does. It&#39;s a pass-through proxy that logs messages without modifying them:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
XCBBUILDSERVICE_PATH=/path/to/XCBLoggingBuildService xcodebuild build    </shiki-highlight>
  </div>
</div>
<p>
The protocol isn&#39;t hidden. It&#39;s open source, documented in code, and Xcode explicitly supports swapping out the implementation. The pieces are all there for anyone who wants to build better observability into their build process.</p>
<h2 id="making-builds-agent-friendly" tabindex="-1" class="marketing__blog_post__body__content__heading">
Making Builds Agent-Friendly<a href="#making-builds-agent-friendly" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Making Builds Agent-Friendly"></a></h2>
<p>
Capturing build messages is only half the problem. The other half is making that data useful for AI agents.</p>
<p>
If you just dump raw protocol messages into an agent&#39;s context, you&#39;ll quickly run into limits. A single build can generate thousands of messages. That&#39;s way too much for any reasonable context window, and most of it isn&#39;t relevant to whatever question you&#39;re trying to answer.</p>
<p>
We need to think about this differently. Instead of giving agents raw data, we need to give them the right data at the right level of detail.</p>
<h3 id="the-correlation-problem" tabindex="-1" class="marketing__blog_post__body__content__heading">
The correlation problem<a href="#the-correlation-problem" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The correlation problem"></a></h3>
<p>
There&#39;s a practical challenge we hit immediately: how do you connect a build invocation to its data?</p>
<p>
When an agent runs <code class="inline">xcodebuild</code>, it needs some way to later ask &quot;what happened in that build?&quot; The build service doesn&#39;t automatically tag its output with any kind of identifier. If you&#39;re running multiple builds, or if you want to query historical data, you need a way to correlate them.</p>
<p>
One approach is to pass a build ID through an environment variable. The agent generates a unique ID before invoking the build:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
BUILD_ID=$(uuidgen)
XCBBUILDSERVICE_PATH=/path/to/logging-service \
  BUILD_TRACE_ID=$BUILD_ID \
  xcodebuild build -scheme MyApp    </shiki-highlight>
  </div>
</div>
<p>
The logging service reads <code class="inline">BUILD_TRACE_ID</code> from the environment and tags all captured messages with it. Later, the agent can query using that same ID.</p>
<p>
This sounds simple, but it&#39;s the kind of glue that makes the difference between a demo and something actually usable. Without correlation, you&#39;re stuck with &quot;show me the last build&quot; and hoping there wasn&#39;t a concurrent build that interleaved with it.</p>
<h3 id="storing-build-data" tabindex="-1" class="marketing__blog_post__body__content__heading">
Storing build data<a href="#storing-build-data" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Storing build data"></a></h3>
<p>
Where would you put all these messages? SQLite seems like a natural fit.</p>
<p>
It might seem like overkill, but SQLite has some nice properties for this use case. It&#39;s a single file, so there&#39;s nothing to set up. It&#39;s queryable, so agents can ask specific questions without loading everything into memory. And it&#39;s portable, so you can copy build history between machines or share it with teammates.</p>
<p>
The key insight is that you wouldn&#39;t want to store raw messages and query them directly. You&#39;d want to pre-compute the things agents are likely to ask about. Think of it as layers:</p>
<p>
<strong>Summary layer.</strong> One row per build with pre-computed metrics: total duration, number of targets, number of tasks, error count, warning count, cache hit rate, whether it succeeded or failed. This is maybe 50 tokens. An agent can get a high-level view of any build almost for free.</p>
<p>
<strong>Top-N layer.</strong> The slowest targets, the slowest tasks, the most recent errors. Pre-sorted and limited. If an agent asks &quot;why was this build slow?&quot;, you can answer with a couple hundred tokens instead of dumping the entire task list.</p>
<p>
<strong>Details layer.</strong> Individual diagnostics, task timing breakdowns, the full error messages with file locations. You only fetch this when drilling down into something specific.</p>
<p>
<strong>Raw layer.</strong> The original messages, stored as JSON. Almost never accessed, but there if you need to debug something weird or answer a question the other layers don&#39;t cover.</p>
<p>
The schema might look something like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sql    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sql">
-- Summary layer: one row per build with pre-computed metrics
CREATE TABLE builds (
  id TEXT PRIMARY KEY,
  build_id INTEGER,
  started_at TEXT NOT NULL,
  ended_at TEXT,
  status TEXT,
  duration_seconds REAL,
  target_count INTEGER DEFAULT 0,
  task_count INTEGER DEFAULT 0,
  error_count INTEGER DEFAULT 0,
  warning_count INTEGER DEFAULT 0,
  cache_hit_count INTEGER DEFAULT 0,
  cache_miss_count INTEGER DEFAULT 0
);

-- Details layer: individual targets with timing data
CREATE TABLE build_targets (
  id INTEGER PRIMARY KEY,
  build_id TEXT NOT NULL,
  target_id INTEGER NOT NULL,
  guid TEXT NOT NULL,
  name TEXT NOT NULL,
  project_name TEXT,
  configuration_name TEXT,
  started_at TEXT NOT NULL,
  ended_at TEXT,
  duration_seconds REAL,
  task_count INTEGER DEFAULT 0,
  status TEXT
);

-- Details layer: individual tasks with timing and resource metrics
CREATE TABLE build_tasks (
  id INTEGER PRIMARY KEY,
  build_id TEXT NOT NULL,
  task_id INTEGER NOT NULL,
  target_id INTEGER,
  parent_id INTEGER,
  task_name TEXT,
  rule_info TEXT,
  execution_description TEXT,
  interesting_path TEXT,
  started_at TEXT NOT NULL,
  ended_at TEXT,
  status TEXT,
  duration_seconds REAL,
  utime_usec INTEGER,
  stime_usec INTEGER,
  max_rss_bytes INTEGER,
  was_cache_hit INTEGER DEFAULT 0
);

-- Details layer: structured diagnostics with file locations
CREATE TABLE build_diagnostics (
  id INTEGER PRIMARY KEY,
  build_id TEXT NOT NULL,
  kind TEXT NOT NULL,
  message TEXT NOT NULL,
  file_path TEXT,
  line INTEGER,
  column_number INTEGER,
  target_id INTEGER,
  task_id INTEGER,
  timestamp TEXT NOT NULL
);

-- Dependency graph: target dependencies for bottleneck analysis
CREATE TABLE target_dependencies (
  id INTEGER PRIMARY KEY,
  build_id TEXT NOT NULL,
  target_guid TEXT NOT NULL,
  depends_on_guid TEXT NOT NULL
);

-- Top-N layer: pre-sorted views for common queries
CREATE VIEW slowest_targets AS
SELECT build_id, name, project_name, duration_seconds, task_count, status
FROM build_targets
WHERE duration_seconds IS NOT NULL
ORDER BY build_id, duration_seconds DESC;

CREATE VIEW slowest_tasks AS
SELECT build_id, task_name, execution_description, interesting_path,
       duration_seconds, utime_usec, stime_usec, max_rss_bytes
FROM build_tasks
WHERE duration_seconds IS NOT NULL AND was_cache_hit = 0
ORDER BY build_id, duration_seconds DESC;    </shiki-highlight>
  </div>
</div>
<p>
Nothing fancy. The point is to make common queries fast and cheap.</p>
<h3 id="exposing-data-to-agents" tabindex="-1" class="marketing__blog_post__body__content__heading">
Exposing data to agents<a href="#exposing-data-to-agents" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Exposing data to agents"></a></h3>
<p>
Once you have the data stored, how do agents access it?</p>
<p>
The simplest approach is a CLI. Agents can already execute shell commands, so there&#39;s no need for a separate server or protocol. A CLI built into the same executable that captures the data could expose commands like:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# High-level summary of a build
SWBBuildService trace summary --build latest

# What went wrong?
SWBBuildService trace errors --build latest

# Why was it slow?
SWBBuildService trace slowest-targets --build latest --limit 5
SWBBuildService trace slowest-tasks --build latest --limit 10

# Find parallelization bottlenecks
SWBBuildService trace bottlenecks --build latest

# Show the critical path
SWBBuildService trace critical-path --build latest

# Compare two builds
SWBBuildService trace diff --builds abc123 def456

# Find historical patterns
SWBBuildService trace search-errors --pattern &quot;linker&quot;    </shiki-highlight>
  </div>
</div>
<p>
The agent just calls the command and gets back structured output. No server to run, no protocol to implement. The CLI handles the database queries and returns JSON or human-readable output depending on what&#39;s needed.</p>
<p>
You could support convenient aliases too. Instead of requiring exact build IDs, let agents say <code class="inline">latest</code> for the most recent build, <code class="inline">latest:MyScheme</code> for the most recent build of a specific scheme, or <code class="inline">failed</code> for the most recent failure.</p>
<h2 id="real-build-analysis:-wikipedia-ios" tabindex="-1" class="marketing__blog_post__body__content__heading">
Real Build Analysis: Wikipedia iOS<a href="#real-build-analysis:-wikipedia-ios" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Real Build Analysis: Wikipedia iOS"></a></h2>
<img style="width: 100px; max-width: 100px;" alt="Wikipedia iOS app icon" src="/marketing/images/blog/2025/11/27/teaching-ai-to-read-xcode-builds/wikipedia-app-icon.png">
<p>
To validate this approach, we instrumented a real build of the <a href="https://github.com/wikimedia/wikipedia-ios">Wikipedia iOS app</a>, a large open-source project with 19 targets and thousands of tasks. Here&#39;s what the build service captured:</p>
<h3 id="build-summary" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build Summary<a href="#build-summary" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build Summary"></a></h3>
<p>
A clean build completed in 457 seconds, spanning 19 targets and 3,303 individual tasks. Zero cache hits because we started fresh. The build succeeded with 86 warnings that would be worth investigating.</p>
<h3 id="identifying-bottlenecks" tabindex="-1" class="marketing__blog_post__body__content__heading">
Identifying Bottlenecks<a href="#identifying-bottlenecks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Identifying Bottlenecks"></a></h3>
<p>
This is where the dependency graph becomes invaluable. By analyzing which targets block other targets and how long they take, we can compute a &quot;bottleneck score&quot; (duration x dependent count).</p>
<p>
<strong>The <code class="inline">WMF</code> framework is the critical bottleneck.</strong> It takes 246 seconds and blocks 4 other targets from starting: <code class="inline">ContinueReadingWidget</code>, <code class="inline">Wikipedia</code>, <code class="inline">WidgetsExtension</code>, and <code class="inline">NotificationServiceExtension</code>. The app extensions all depend on it. If you wanted to improve build times, this is where to focus: either splitting <code class="inline">WMF</code> into smaller, more independent modules, or finding ways to parallelize work within it.</p>
<p>
Other notable bottlenecks include <code class="inline">CocoaLumberjack</code> (34s, blocking 3 targets) and the individual app extensions (each around 252s, blocking the main <code class="inline">Wikipedia</code> target).</p>
<h3 id="the-critical-path" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Critical Path<a href="#the-critical-path" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Critical Path"></a></h3>
<p>
Using the dependency graph, we can compute the longest chain of dependencies that determines the minimum possible build time: <code class="inline">WMF</code> (246s) -&gt; <code class="inline">ContinueReadingWidget</code> (253s) -&gt; <code class="inline">Wikipedia</code> (456s), totaling 955 seconds of serial work.</p>
<p>
This tells us something important: if these targets ran sequentially, the build would take 955 seconds. The actual build took 457 seconds, meaning we achieved roughly 2.1x speedup through parallelization. But we can also see the limit: no amount of parallelization can make this build faster than whatever is on the critical path.</p>
<h3 id="slowest-targets" tabindex="-1" class="marketing__blog_post__body__content__heading">
Slowest Targets<a href="#slowest-targets" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Slowest Targets"></a></h3>
<p>
The five slowest targets tell an interesting story: <code class="inline">Wikipedia</code> (456s, 926 tasks), <code class="inline">ContinueReadingWidget</code> (253s, 61 tasks), <code class="inline">WidgetsExtension</code> (252s, 95 tasks), <code class="inline">NotificationServiceExtension</code> (252s, 60 tasks), and <code class="inline">WMF</code> (246s, 902 tasks).</p>
<p>
Notice that <code class="inline">ContinueReadingWidget</code> takes 253 seconds but only has 61 tasks, while <code class="inline">WMF</code> has 902 tasks but takes slightly less time. This suggests the widget&#39;s compilation is CPU-bound on a few expensive files, while <code class="inline">WMF</code> has better internal parallelization.</p>
<h3 id="slowest-tasks" tabindex="-1" class="marketing__blog_post__body__content__heading">
Slowest Tasks<a href="#slowest-tasks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Slowest Tasks"></a></h3>
<p>
Drilling into individual tasks reveals optimization opportunities. Asset catalog compilation was the slowest single task at 131 seconds, using 3.1 MB of memory. This is nearly a third of the critical path target&#39;s time, and it runs as a single task that can&#39;t be parallelized.</p>
<p>
The next slowest was a batch Swift compilation (83 seconds, 373.7 MB) covering 25 files including <code class="inline">ArticleURLListViewController.swift</code> and <code class="inline">DonateFunnel.swift</code>. Individual Swift file compilations showed similar times around 81 seconds because they&#39;re compiled together in the batch.</p>
<h3 id="what-an-agent-could-do-with-this" tabindex="-1" class="marketing__blog_post__body__content__heading">
What an Agent Could Do With This<a href="#what-an-agent-could-do-with-this" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What an Agent Could Do With This"></a></h3>
<p>
Armed with this data, an AI agent could provide actionable recommendations:</p>
<blockquote>
  <p>
&quot;Your Wikipedia iOS build took 457 seconds. The main bottleneck is the <code class="inline">WMF</code> framework (246s), which blocks 4 other targets. Consider:  </p>
  <ol>
    <li>
      <p>
<strong>Split WMF</strong>: The framework has 902 build tasks. Breaking it into 2-3 smaller frameworks could allow better parallelization.      </p>
    </li>
    <li>
      <p>
<strong>Asset catalog optimization</strong>: Asset catalog compilation takes 131 seconds and runs serially. Consider breaking the catalog into smaller, per-feature catalogs that can compile in parallel.      </p>
    </li>
    <li>
      <p>
<strong>Build order insight</strong>: Your critical path is WMF -&gt; ContinueReadingWidget -&gt; Wikipedia. The theoretical minimum build time with infinite parallelization is 955 seconds serial time, you&#39;re achieving 2.1x parallelization.      </p>
    </li>
    <li>
      <p>
<strong>86 warnings to fix</strong>: These don&#39;t affect build time, but fixing them will reduce noise and potential future issues.&quot;      </p>
    </li>
  </ol>
</blockquote>
<p>
This isn&#39;t guessing based on log output. It&#39;s analysis based on actual dependency relationships, task timing, and resource metrics that the build system tracks internally.</p>
<h2 id="what-this-requires" tabindex="-1" class="marketing__blog_post__body__content__heading">
What This Requires<a href="#what-this-requires" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What This Requires"></a></h2>
<p>
This exploration demonstrates what&#39;s possible, but turning it into a robust tool requires acknowledging some challenges.</p>
<h3 id="protocol-stability" tabindex="-1" class="marketing__blog_post__body__content__heading">
Protocol Stability<a href="#protocol-stability" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Protocol Stability"></a></h3>
<p>
The swift-build protocol is now open source, which is a significant step forward. What would make this truly useful is Apple officializing it: giving <code class="inline">xcodebuild</code> a flag to specify where to store build trace data (a SQLite database path), and providing a CLI interface to query that data. We&#39;ve built exactly this in our exploration, and Apple could do the same with proper support. They&#39;d need to standardize the data schema and handle migrations when the schema evolves across Xcode versions.</p>
<h3 id="what's-already-possible-with-post-build-artifacts" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s already possible with post-build artifacts<a href="#what's-already-possible-with-post-build-artifacts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's already possible with post-build artifacts"></a></h3>
<p>
Before diving into what protocol-level access would unlock, it&#39;s worth recognizing what&#39;s already achievable today. Xcode generates <code class="inline">.xcactivitylog</code> files (gzip-compressed build logs with structured data) and <code class="inline">.xcresultbundle</code> directories (containing test results, code coverage, and build metadata). These artifacts contain a wealth of information that tools can parse after builds complete.</p>
<p>
Tools like <a href="https://github.com/MobileNativeFoundation/xclogparser">xclogparser</a> have been parsing these files for years, extracting timing data, warnings, and errors into queryable formats. This post-hoc approach works well for many use cases: you can analyze build performance, track warning trends over time, and identify slow compilation units.</p>
<p>
At <a href="https://tuist.dev/">Tuist</a>, we&#39;ve built exactly this. Our <a href="https://docs.tuist.dev/en/guides/features/insights">Build Insights</a> feature parses <code class="inline">.xcactivitylog</code> and <code class="inline">.xcresultbundle</code> files to provide teams with dashboards showing build times, cache effectiveness, and historical trends. The data spans across developers, CI pipelines, and time, giving teams visibility into patterns they&#39;d never notice from individual builds. And we&#39;re extending this to tests too: <a href="https://tuist.dev/tuist/tuist/tests/">Test Insights</a> (already available in our public dashboard) will bring the same cross-time, cross-space analysis to your test suite. Adopting it is as simple as adding a post-action to your Xcode schemes.</p>
<p>
This matters because much of what we&#39;ve described in the &quot;Vision&quot; section, like team-wide build intelligence and build archaeology, is achievable with post-build artifacts. You don&#39;t need Apple to bless a new extension point to start getting value from structured build data.</p>
<h3 id="why-protocol-level-access-would-still-matter" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why protocol-level access would still matter<a href="#why-protocol-level-access-would-still-matter" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why protocol-level access would still matter"></a></h3>
<p>
So if we can already parse <code class="inline">.xcactivitylog</code> files, why bother with the build protocol at all?</p>
<p>
The key differences come down to timing and data availability.</p>
<p>
<strong>Real-time intervention.</strong> When you parse post-build artifacts, the build is already done. An AI agent watching the protocol stream could notice a problem mid-build and take action: pause the build, alert the developer, or even suggest a fix while there&#39;s still time to act on it. With post-hoc parsing, you&#39;re always reacting to something that already happened.</p>
<p>
<strong>Rebuild causality.</strong> The protocol includes <code class="inline">BuildOperationBacktraceFrameEmitted</code> messages that explain <em>why</em> each task was rebuilt: was it because the rule never ran before? Because the signature changed? Because an input was rebuilt? This causal chain is invaluable for debugging incremental build issues, but it&#39;s ephemeral. It flows through the protocol during planning and execution, then disappears. Result bundles record that a task ran, but not the decision tree that led to it running.</p>
<p>
<strong>Live dependency graph computation.</strong> The protocol exposes <code class="inline">ComputeDependencyGraphRequest</code> and <code class="inline">ComputeDependencyGraphResponse</code> messages showing how dependencies are resolved during planning. You can see the actual adjacency lists of target-to-target dependencies as the build system computes them. This information exists in the protocol as it happens, but the result bundle only contains the final build output, not the planning decisions.</p>
<p>
<strong>Real-time progress.</strong> <code class="inline">BuildOperationProgressUpdated</code> messages stream live status with target names, status messages, and completion percentages. You could build a web dashboard showing your build&#39;s progress in real-time, with tasks appearing and completing as they happen. This enables experiences like watching your CI build live from anywhere, something that&#39;s not possible with post-hoc parsing.</p>
<p>
<strong>Per-task resource attribution.</strong> While result bundles contain aggregate timing data, the protocol streams per-task metrics as each task completes: user-mode CPU time, system CPU time, peak memory usage, and wall-clock duration. This granularity makes it possible to identify not just which targets are slow, but which specific compilation units within those targets are consuming resources.</p>
<h3 id="what-would-make-this-better" tabindex="-1" class="marketing__blog_post__body__content__heading">
What would make this better<a href="#what-would-make-this-better" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What would make this better"></a></h3>
<p>
If Apple designed an extensible architecture where anyone can hook into the build event stream, the community could build powerful tooling on top of it. A stable contract for build events would enable real-time build monitoring in CI dashboards, AI agents that can intervene during builds, and custom workflows we haven&#39;t imagined yet.</p>
<p>
The pieces are already there in swift-build. What&#39;s missing is Apple blessing this as an official extension point rather than an implementation detail that might change without notice.</p>
<h2 id="the-vision:-where-this-could-go" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Vision: Where This Could Go<a href="#the-vision:-where-this-could-go" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Vision: Where This Could Go"></a></h2>
<p>
The Wikipedia iOS analysis shows what&#39;s possible with a single build. But the real potential emerges when you think about builds over time.</p>
<p>
Much of what follows is achievable today by parsing <code class="inline">.xcactivitylog</code> and <code class="inline">.xcresultbundle</code> files after builds complete. That&#39;s exactly what we&#39;re building at Tuist with <a href="https://docs.tuist.dev/en/guides/features/insights">Build Insights</a>. Protocol-level access would add real-time capabilities and richer causality data, but you don&#39;t need to wait for Apple to start getting value from structured build observability.</p>
<h3 id="team-wide-build-intelligence" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team-Wide Build Intelligence<a href="#team-wide-build-intelligence" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team-Wide Build Intelligence"></a></h3>
<p>
Imagine a CI system that captures structured build data from every pull request. Over weeks and months, patterns emerge:</p>
<ul>
  <li>
Which targets get slower as the codebase grows  </li>
  <li>
Which developers&#39; changes tend to invalidate more cache entries  </li>
  <li>
What times of day have the slowest builds (and why)  </li>
  <li>
How merge queue builds differ from individual PR builds  </li>
</ul>
<p>
This isn&#39;t theoretical, it&#39;s the kind of analysis that large companies do manually with custom tooling. Structured build data makes it accessible to everyone. And it&#39;s achievable today: post-build artifacts contain all the timing data, target information, and warning counts you need to build these dashboards.</p>
<h3 id="proactive-developer-assistance" tabindex="-1" class="marketing__blog_post__body__content__heading">
Proactive Developer Assistance<a href="#proactive-developer-assistance" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Proactive Developer Assistance"></a></h3>
<p>
With historical data and dependency information, agents could provide guidance before you even start a build:</p>
<blockquote>
  <p>
&quot;You&#39;re about to modify <code class="inline">Constants.swift</code>. Based on build history, this file is imported by 847 other files and will trigger a near-clean rebuild. Would you like me to suggest a more targeted approach?&quot;  </p>
</blockquote>
<p>
Or during code review:</p>
<blockquote>
  <p>
&quot;This PR adds a new import to <code class="inline">SharedFramework.h</code>. Our build data shows this header is included by 12 targets. This change will add approximately 45 seconds to incremental builds for those targets.&quot;  </p>
</blockquote>
<p>
These insights come from correlating build data over time with code changes. The build artifacts contain timing data; the git history contains what changed. An AI agent with access to both can make these connections.</p>
<h3 id="real-time-build-monitoring" tabindex="-1" class="marketing__blog_post__body__content__heading">
Real-Time Build Monitoring<a href="#real-time-build-monitoring" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Real-Time Build Monitoring"></a></h3>
<p>
This is where protocol-level access becomes essential. The build service generates events in real time, and an agent could watch these events as they happen:</p>
<blockquote>
  <p>
&quot;Build in progress... The <code class="inline">Analytics</code> target is taking longer than usual (45s vs. typical 30s). This started after yesterday&#39;s PR that added 3 new tracking events. The additional compile time is coming from type inference in <code class="inline">EventBuilder.swift</code>.&quot;  </p>
</blockquote>
<p>
Post-hoc parsing can tell you that <code class="inline">Analytics</code> was slow after the fact. Protocol-level access could tell you while it&#39;s happening, giving you the option to stop the build, investigate, or take corrective action before wasting more CI minutes.</p>
<h3 id="build-archaeology" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build Archaeology<a href="#build-archaeology" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build Archaeology"></a></h3>
<p>
When something goes wrong weeks later, structured data lets you investigate:</p>
<blockquote>
  <p>
&quot;This linker error started appearing 3 days ago. Looking at build history, the last successful build was commit <code class="inline">abc123</code>. Between then and the first failure, there were 7 commits. The failure correlates with the addition of <code class="inline">NewFeature.framework</code> without updating the library search paths.&quot;  </p>
</blockquote>
<p>
This kind of analysis is entirely achievable with post-build artifacts. You need a database of historical builds with their errors, timing, and associated commits. Then it&#39;s a matter of querying and correlation, exactly what AI agents excel at.</p>
<p>
The build system already knows everything it needs to answer these questions. The data is available in post-build artifacts. We just need to capture and expose it in a way that&#39;s useful.</p>
<h2 id="key-learnings" tabindex="-1" class="marketing__blog_post__body__content__heading">
Key Learnings<a href="#key-learnings" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Key Learnings"></a></h2>
<p>
Building this exploration taught us several things:</p>
<p>
<strong>The build system is far more sophisticated than it appears.</strong> What looks like &quot;compile a bunch of files&quot; is actually a complex graph scheduler with caching, parallelization, and detailed instrumentation. The data is there, it&#39;s just not exposed.</p>
<p>
<strong>Structured data fundamentally changes what AI can do.</strong> An agent parsing &quot;CompileSwift normal arm64...&quot; has almost nothing to work with. The same agent given structured events with timing, dependencies, and metrics can provide genuinely useful analysis.</p>
<p>
<strong>Context window efficiency matters.</strong> You can&#39;t dump 3000 build tasks into a prompt. The tiered approach (summary -&gt; top-N -&gt; details -&gt; raw) makes the difference between &quot;unusable&quot; and &quot;practical.&quot;</p>
<p>
<strong>Dependency graphs are the key to build optimization.</strong> Knowing that WMF blocks 4 targets is far more actionable than knowing WMF takes 246 seconds. The graph tells you what to fix; timing alone just tells you something is slow.</p>
<p>
<strong>Build observability is underinvested.</strong> Developers lose hours to build issues that could be diagnosed in minutes with better tooling. The gap between &quot;what the build system knows&quot; and &quot;what developers can see&quot; is enormous.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s Next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's Next"></a></h2>
<p>
There are two parallel paths forward, and we&#39;re actively working on both.</p>
<h3 id="what-you-can-use-today" tabindex="-1" class="marketing__blog_post__body__content__heading">
What you can use today<a href="#what-you-can-use-today" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What you can use today"></a></h3>
<p>
At Tuist, we&#39;re building <a href="https://docs.tuist.dev/en/guides/features/insights">Build Insights</a> and <a href="https://tuist.dev/tuist/tuist/tests/">Test Insights</a> using post-build artifacts. This works today, requires no experimental tooling, and gives teams visibility into build performance across developers, CI pipelines, and time. Adopting it is as simple as adding a post-action to your Xcode schemes that uploads your <code class="inline">.xcactivitylog</code> and <code class="inline">.xcresultbundle</code> files.</p>
<p>
This is the pragmatic path: you don&#39;t need Apple to bless anything, you don&#39;t need to swap out your build service, and you can start getting value immediately. Team-wide build intelligence, historical trends, warning tracking, and build archaeology are all achievable with post-build parsing.</p>
<h3 id="exploring-real-time-protocol-access" tabindex="-1" class="marketing__blog_post__body__content__heading">
Exploring real-time protocol access<a href="#exploring-real-time-protocol-access" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Exploring real-time protocol access"></a></h3>
<p>
For real-time features and richer causality data, we&#39;ve open-sourced <a href="https://github.com/tuist/argus">Argus</a>, a fork of swift-build that provides an agentic interface for AI agents. This is very much an experiment. It demonstrates what&#39;s possible when you tap into the build event stream directly, including features that post-hoc parsing cannot provide:</p>
<ul>
  <li>
<strong>Real-time monitoring</strong>: Watch your build progress live in a dashboard  </li>
  <li>
<strong>Mid-build intervention</strong>: An agent could pause a build when it detects a problem  </li>
  <li>
<strong>Rebuild causality</strong>: Understand <em>why</em> tasks were rebuilt, not just that they were  </li>
  <li>
<strong>Live dependency resolution</strong>: See how the build system computes dependencies during planning  </li>
</ul>
<p>
Install Argus globally using <a href="https://mise.jdx.dev/">mise</a>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mise use -g github:tuist/argus    </shiki-highlight>
  </div>
</div>
<p>
Then add the following to your agent&#39;s memory or system prompt to enable build observability:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
When running Xcode builds, use Argus to capture and analyze build data:

1. Run builds with Argus and a session ID for correlation:
   BUILD_TRACE_ID=$(uuidgen)
   XCBBUILDSERVICE_PATH=$(which argus) BUILD_TRACE_ID=$BUILD_TRACE_ID xcodebuild build -scheme MyScheme

2. Query build results using the session ID:
   argus trace summary --build $BUILD_TRACE_ID
   argus trace errors --build $BUILD_TRACE_ID
   argus trace slowest-targets --build $BUILD_TRACE_ID --limit 5
   argus trace bottlenecks --build $BUILD_TRACE_ID

   Or use &quot;latest&quot; to query the most recent build:
   argus trace summary --build latest

3. Use --json flag for programmatic access:
   argus trace summary --build $BUILD_TRACE_ID --json

4. Run `argus trace --help` to discover all available commands.    </shiki-highlight>
  </div>
</div>
<p>
If you have ideas for how to improve things, open PRs or issues on the <a href="https://github.com/tuist/argus">Argus repository</a>. We&#39;d love to see what you build with it, so share your learnings on <a href="https://fosstodon.org/@tuist">Mastodon</a>, <a href="https://bsky.app/profile/tuist.dev">Bluesky</a>, or <a href="https://www.linkedin.com/company/tuistio">LinkedIn</a> and tag us.</p>
<p>
Check out the <a href="https://github.com/swiftlang/swift-build">swift-build repository</a> to see the protocol definitions, join the <a href="https://community.tuist.dev/">Tuist community</a> to discuss build optimization, or <a href="https://cal.tuist.dev/team/tuist/tuist">book a call</a> if you need help scaling your development workflows.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Registry: an open Swift Package Registry ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist Registry is an open Swift Package Registry for fast SwiftPM resolution—no authentication required. ]]></summary>
      <link href="https://tuist.dev/blog/2025/11/26/opening-registry"/>
      <id>https://tuist.dev/blog/2025/11/26/opening-registry</id>
      <updated>Wed, 26 Nov 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
We <a href="/blog/2025/01/22/announcing-tuist-registry/">released</a> Tuist Registry earlier this year as an open Swift Package Registry, helping teams to resolve their packages more reliably, efficiently, and <strong>faster</strong>.</p>
<p>
Since launch, the registry has grown to serve almost 10,000 packages and more than 160,000 releases. Teams using the registry have seen disk space savings of up to 91% – from 6.6 GB down to 600 MB – and CI cache restore times dropping from 2 minutes to less than 20 seconds.</p>
<p>
As teams started to integrate the registry, one point of friction has become clear: the registry required a Tuist account and authentication. Something developers are not used to when downloading open source packages from other registries in ecosystems like npm or CocoaPods. Having now understood better how teams use the registry, we have decided to remove the need for authentication and account creation. Now, anyone can use the registry without any additional steps. The same security measures remain in place – packages are sourced directly from their original repositories and the Swift CLI or Xcode verifies checksums on every download.</p>
<h2 id="setting-up-the-tuist-registry" tabindex="-1" class="marketing__blog_post__body__content__heading">
Setting up the Tuist registry<a href="#setting-up-the-tuist-registry" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Setting up the Tuist registry"></a></h2>
<p>
Thanks to the registry being open now, the only thing you need to do is to run the following command in your project (install the CLI first by following <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist">these instructions</a>):</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist registry setup    </shiki-highlight>
  </div>
</div>
<p>
This command will configure the Tuist Registry for your project – regardless of your setup. This command works with standard Xcode projects, generated Xcode projects, and Swift packages. For Swift packages, you can even use directly the <code class="inline">swift</code> CLI:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
swift package-registry set https://tuist.dev/api/registry/swift    </shiki-highlight>
  </div>
</div>
<p>
Either of these commands will create a configuration file, with its location depending on your setup. For Swift packages, this would be in <code class="inline">.swiftpm/configuration/registries.json</code>, for Xcode projects, it would be in <code class="inline">YourProject.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/configuration/registries.json</code>. Make sure to commit this configuration file, so all your colleagues and your CI have access to the registry.</p>
<p>
When unauthenticated, you will be rate-limited to 10,000 requests per minute – more than enough for resolving hundreds of packages in a typical clean build. If you are running into limits, you can still authenticate with your Tuist account to increase your rate limit to 100,000 requests per minute:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist registry login    </shiki-highlight>
  </div>
</div>
<p>
But for typical workflows, the current limits should be more than enough. If not, please <a href="mailto:contact@tuist.dev">reach out to us</a>, we&#39;d love to know, so we can adjust the rate limits to accommodate typical workflows.</p>
<p>
If you&#39;re already using the registry, we recommend re-running <code class="inline">tuist registry setup</code> to update your configuration file with the new endpoint that allows unauthenticated access.</p>
<h2 id="what's-next?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next?<a href="#what's-next?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next?"></a></h2>
<p>
We believe that to provide the best experience, we need to use our own tools daily. Opening the registry has allowed us to integrate the registry in our <a href="https://github.com/tuist/tuist">monorepository</a> where all of our Swift packages are installed via the Tuist Registry, which we&#39;ve done as part of <a href="https://github.com/tuist/tuist/pull/8712">this PR</a>.</p>
<p>
Now that the registry is open, our next step will be to allow authenticated organizations to publish their own packages to a private registry, so they can move <em>all</em> of their packages away from the source control resolution and improve the resolution of both open source and internal packages.</p>
<p>
And as always, we&#39;re keen to hear your feedback – do you have any suggestions or ideas for how we can improve the registry? We&#39;d love to <a href="mailto:contact@tuist.dev">hear from you</a>!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Build Smart Before You Build Fast ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Discover how merge throughput evolves as your team grows, and why optimizing build and test times becomes critical for business velocity ]]></summary>
      <link href="https://tuist.dev/blog/2025/11/17/smart-before-fast"/>
      <id>https://tuist.dev/blog/2025/11/17/smart-before-fast</id>
      <updated>Mon, 17 Nov 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
You&#39;re about to live through a story that every engineering leader eventually experiences. It&#39;s a story about growth, about success, and about an invisible tax that quietly erodes everything you&#39;ve built. It starts with velocity. Then it ends with waiting.</p>
<p>
In systems thinking, there&#39;s a pattern called <a href="https://thesystemsthinker.com/shifting-the-burden-moving-beyond-a-reactive-orientation/">&quot;Shifting the Burden&quot;</a>, identified by Peter Senge in <a href="https://www.penguinrandomhouse.com/books/163376/the-fifth-discipline-by-peter-m-senge/">&quot;The Fifth Discipline&quot;</a>, where organizations repeatedly apply symptomatic solutions that provide quick relief while the fundamental problem grows worse. When build times slow down, companies buy faster hardware. When throughput drops, they hire more developers. When coordination fails, they rewrite everything in a different technology. These solutions feel productive because they&#39;re tangible and immediate. But they&#39;re treating symptoms, not the disease. And with each symptomatic fix, the organization becomes more dependent on them, while losing the capability to solve the underlying problem.</p>
<p>
This is that story. And it costs companies millions before they realize what&#39;s happening.</p>
<h2 id="the-metric-that-rules-everything" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Metric That Rules Everything<a href="#the-metric-that-rules-everything" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Metric That Rules Everything"></a></h2>
<p>
There&#39;s a number that strongly signals whether your engineering organization is thriving or drowning. It&#39;s not lines of code. It&#39;s not story points. It&#39;s not even bugs per release. It&#39;s <strong>merge throughput</strong>: how many code changes successfully make it into your main branch each day. This metric tells you how fast features reach your customers, how quickly bugs get fixed, how rapidly you can respond to market demands. It&#39;s the heartbeat of your engineering organization.</p>
<p>
And here&#39;s what most engineering leaders don&#39;t realize until it&#39;s too late: as your team grows, this number can actually go down. Sometimes dramatically. Let me show you what&#39;s coming.</p>
<h2 id="phase-1:-the-lone-wolf" tabindex="-1" class="marketing__blog_post__body__content__heading">
Phase 1: The Lone Wolf<a href="#phase-1:-the-lone-wolf" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Phase 1: The Lone Wolf"></a></h2>
<p>
You launch your startup on a Tuesday. You&#39;re a solo founder who codes, armed with Claude and GitHub Copilot as your pair programmers. No team. No process. No friction. You push straight to main. Multiple times a day, every day. There are no code reviews because there&#39;s nobody to review with. There are no merge conflicts because you&#39;re the only one committing. There&#39;s no CI pipeline slowing you down because every bug that slips through goes straight into the weekly release to your five beta users who are just happy the app exists.</p>
<p>
With your AI coding assistants writing boilerplate and suggesting implementations, you&#39;re moving at a pace that would have seemed impossible five years ago. The merge throughput is pure: one developer, zero overhead. This is the golden age. This is what velocity feels like.</p>
<iframe src="/blog/2025/11/17/smart-before-fast/iframe.html?id=lone_wolf" width="100%" height="400" frameborder="0" data-visualization="data-visualization">
</iframe>
<p>
But your app is growing. Users are signing up. And one bad commit ships a critical bug in your weekly release because there was no safety net. That&#39;s when you realize: pure velocity without quality control is just recklessness in disguise.</p>
<h2 id="phase-2:-adding-safety-nets" tabindex="-1" class="marketing__blog_post__body__content__heading">
Phase 2: Adding Safety Nets<a href="#phase-2:-adding-safety-nets" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Phase 2: Adding Safety Nets"></a></h2>
<p>
You set up GitHub Actions. You create a branch called &quot;develop&quot; and promise yourself you&#39;ll only merge to main after tests pass. You hire your first engineer, Marcus, who&#39;s also using AI coding tools to write code faster. Now when you want to ship a feature, you open a pull request. The CI kicks off, running tests and linting. Marcus reviews your code. Then it merges. When Marcus ships code, you review. The cycle repeats.</p>
<p>
You&#39;re still moving fast, though not quite as fast as before. Once or twice a week you run into a merge conflict because you both touched the same file, but it&#39;s quick to resolve. Occasionally a test fails randomly, and you just rerun the CI. Your team of two has added some overhead per commit. But you&#39;ve also stopped shipping bugs in your weekly releases. It&#39;s a worthy trade-off.</p>
<iframe src="/blog/2025/11/17/smart-before-fast/iframe.html?id=safety_nets" width="100%" height="400" frameborder="0" data-visualization="data-visualization">
</iframe>
<p>
The app is growing. Revenue is growing. You raise a seed round and decide it&#39;s time to build a real team.</p>
<h2 id="phase-3:-the-team-multiplier" tabindex="-1" class="marketing__blog_post__body__content__heading">
Phase 3: The Team Multiplier<a href="#phase-3:-the-team-multiplier" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Phase 3: The Team Multiplier"></a></h2>
<p>
Six months later, you have five engineers. Everyone has AI assistants helping them write code. The roadmap is ambitious. The team is talented. The codebase has tripled in size. You&#39;d expect throughput to multiply with the team. But that&#39;s not what happens.</p>
<p>
Li opens a PR in the morning. It sits waiting for review because you&#39;re in meetings and Marcus is deep in his own feature. Hours later, you finally review it. You request changes. Li makes the updates, but the CI takes longer now because the test suite has grown. And when it finishes, there&#39;s a merge conflict because Marcus merged something that touched the same service. Li resolves it, reruns CI. By afternoon, one commit finally lands.</p>
<p>
This happens to everyone, all day long. PRs sit in review queues. Merge conflicts happen frequently now that five people are touching overlapping code. The CI occasionally has a flaky test, and nobody&#39;s quite sure which test it is, so they just click &quot;retry.&quot; Many PRs come back with requested changes, adding another round trip. The throughput has grown, but nowhere near what you&#39;d expect from adding three more engineers.</p>
<p>
And then there&#39;s the CI bottleneck. Your provider asked you to estimate how many runners you&#39;d need. That works when your workload is predictable, but it&#39;s not. Nobody&#39;s is. During peak hours, PRs pile up waiting for available runners. Your team sits idle, watching the queue grow. The provider is just leaking the pain of hosting Mac minis to you. They can&#39;t absorb your elastic demand because they don&#39;t operate at the scale you need. You&#39;re not blocked by budget. You&#39;re blocked by infrastructure that can&#39;t keep up.</p>
<iframe src="/blog/2025/11/17/smart-before-fast/iframe.html?id=team_multiplier" width="100%" height="650" frameborder="0" data-visualization="data-visualization">
</iframe>
<p>
You hired three more people and throughput improved, but not nearly as much as you expected. This isn&#39;t what growth is supposed to look like.</p>
<h2 id="phase-4:-the-complexity-wall" tabindex="-1" class="marketing__blog_post__body__content__heading">
Phase 4: The Complexity Wall<a href="#phase-4:-the-complexity-wall" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Phase 4: The Complexity Wall"></a></h2>
<p>
Two years in, your mobile team has grown to 30 engineers. Everyone is shipping code, everyone has AI tools making them more productive than ever, and the feature velocity should be incredible. But something&#39;s wrong.</p>
<p>
The CI now takes 15 to 25 minutes. Nobody remembers who wrote half the tests in the suite. Flaky tests fail frequently, and debugging which test is flaky wastes hours. PRs sit for hours waiting for review because everyone is context-switching between their own features, meetings, and multiple PRs in their queue. When reviews finally happen, many come back with requested changes. More waiting. More CI runs. Merge conflicts happen constantly. When someone finally resolves a conflict and merges, they hold their breath hoping nobody else merged while the CI was running. If they did, back to square one.</p>
<iframe src="/blog/2025/11/17/smart-before-fast/iframe.html?id=complexity_wall" width="100%" height="500" frameborder="0" data-visualization="data-visualization">
</iframe>
<p>
You&#39;re paying millions in engineering salaries and getting a fraction of the output you should. Leadership asks why feature delivery has slowed down. You don&#39;t have a good answer.</p>
<h2 id="phase-5:-the-brute-force-trap" tabindex="-1" class="marketing__blog_post__body__content__heading">
Phase 5: The Brute Force Trap<a href="#phase-5:-the-brute-force-trap" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Phase 5: The Brute Force Trap"></a></h2>
<p>
Your team comes up with a plan. Three plans, actually. Each one sounds reasonable in isolation, but none of them address the root problem:</p>
<p>
<strong>Option 1: Faster Machines</strong>
&quot;We&#39;ll upgrade to the beefiest CI runners GitHub offers,&quot; he says. Sixteen cores instead of four. It&#39;ll cost hundreds of thousands per year, but it&#39;ll cut the CI time in half. Your team calculates the improvement: modest at best.</p>
<p>
<strong>Option 2: More People</strong>
Someone suggests hiring more developers to &quot;parallelize the work.&quot; Another million-plus in salary. But you&#39;ve learned the math by now. More people means more conflicts, longer review queues, even slower CI. Throughput might not move at all. It might even go down.</p>
<p>
<strong>Option 3: Technology Rewrite</strong>
A CTO from your previous company suggests you rewrite everything in React Native. &quot;No compilation step,&quot; he says. &quot;Way faster iteration.&quot; The rewrite would take months, cost your entire team&#39;s focus, and millions in opportunity cost. And at the end, you&#39;d inherit a new set of problems:</p>
<ul>
  <li>
    <p>
<strong>A brittle foundation built on constantly-evolving packages.</strong> The ecosystem moves fast, breaking changes are common, and keeping dependencies up to date becomes a perpetual maintenance burden. What works today might require rewrites tomorrow.    </p>
  </li>
  <li>
    <p>
<strong>A massively expanded security surface.</strong> Instead of relying on platform APIs maintained by Apple and Google, you now depend on hundreds of npm packages, each with their own maintainers, each a potential entry point for supply chain attacks.    </p>
  </li>
  <li>
    <p>
<strong>Platform features become harder to access.</strong> Every time iOS or Android releases a new API, you wait for someone in the community to write a bridge. Native features that should take hours now take days or weeks, assuming someone builds the bridge at all.    </p>
  </li>
  <li>
    <p>
<strong>Performance optimization becomes the default state.</strong> Instead of focusing on building features, your team spends cycles debugging why lists scroll slowly, why animations drop frames, why the app uses too much memory. The abstraction layer adds overhead that you constantly fight against.    </p>
  </li>
</ul>
<p>
But you&#39;d still have the same coordination problems.</p>
<p>
You pick the faster machines because it&#39;s the cheapest mistake. Throughput improves slightly. You&#39;re paying hundreds of thousands a year to make a small dent in the problem. You know you&#39;re treating symptoms, not the disease. The disease is that you&#39;re building and testing everything, every time, for every change, no matter how small. But you don&#39;t know what else to do.</p>
<h2 id="phase-6:-smart-optimization" tabindex="-1" class="marketing__blog_post__body__content__heading">
Phase 6: Smart Optimization<a href="#phase-6:-smart-optimization" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Phase 6: Smart Optimization"></a></h2>
<p>
But there&#39;s an elephant in the room. Something that would be cheaper than all three options, and would have a dramatically better impact.</p>
<p>
What if you didn&#39;t compile and test everything every time? What if you could diff the changes to be selective about what to compile and what to test? When Li changes the authentication module, why are you rebuilding dozens of other modules that didn&#39;t change? When someone touches a networking utility, why are you running the entire test suite instead of just the tests that actually depend on that code?</p>
<p>
Then you talk to an engineering leader at another company who faced the same wall. &quot;We integrated Tuist,&quot; he says. &quot;<a href="https://docs.tuist.dev/en/guides/features/cache">Binary caching</a> and <a href="https://docs.tuist.dev/en/guides/features/selective-testing">selective testing</a>. Changed everything.&quot; The idea is simple: only rebuild what changed, only test what&#39;s affected, and share the cached results across your entire team and CI.</p>
<p>
Your team spends one week integrating Tuist. You set up <a href="https://docs.tuist.dev/guides/develop/build/cache">binary caching</a> so when Li changes the authentication module, the other modules use cached builds from the last time they were compiled. You implement <a href="https://docs.tuist.dev/en/guides/features/selective-testing">selective testing</a> so the CI only runs the tests affected by the change, not the entire suite. The first PR after the optimization merges in minutes instead of an hour.</p>
<p>
Your CI time drops dramatically. The queue disappears because jobs finish faster. Review time drops because fast feedback means reviewers can stay in context. Merge conflicts drop because the faster cycle time means less overlapping work. The merge throughput more than doubles.</p>
<p>
You&#39;re still paying the same in engineering salaries. But now you&#39;re getting dramatically more output. The efficiency more than doubles. You&#39;ve unlocked millions in value. The investment was a fraction of one engineer&#39;s salary per year for Tuist and one month of implementation time. The payback period was measured in days, not years.</p>
<h2 id="what-just-happened" tabindex="-1" class="marketing__blog_post__body__content__heading">
What Just Happened<a href="#what-just-happened" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What Just Happened"></a></h2>
<p>
Let&#39;s trace your journey. At one developer, you had pure efficiency. Zero overhead. At two developers, you maintained most of that efficiency. At five developers, efficiency dropped noticeably. At thirty developers, efficiency crashed. You were getting a fraction of the output you should from your team size.</p>
<p>
After optimization, with the same thirty developers, efficiency more than doubled. Not perfect, but dramatically better than where you were. And here&#39;s the key insight: <strong>you optimized workflows first, not hardware</strong>. Instead of spending hundreds of thousands per year to make your waste happen slightly faster, you spent a fraction of that to eliminate the waste itself. The hardware approach provided marginal gains. The workflow approach transformed the organization.</p>
<h2 id="why-most-companies-get-this-wrong" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why Most Companies Get This Wrong<a href="#why-most-companies-get-this-wrong" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why Most Companies Get This Wrong"></a></h2>
<p>
Here&#39;s the pattern we see repeatedly: companies optimize in the wrong order and waste millions before discovering the right solution.</p>
<p>
Let&#39;s take a typical scenario: a 30-person mobile team with 20-minute CI times. Each developer waits for CI roughly three times a day. That&#39;s 60 minutes per developer per day spent waiting. Across the whole team, you&#39;re wasting the equivalent of 5 full-time engineers just waiting for builds. At an average salary of €140K, that&#39;s €700K per year in wasted time.</p>
<blockquote>
  <p>
&quot;But they can just work on something else while waiting,&quot; you might think. This misses the real cost. Research shows it takes an average of <a href="https://www.ics.uci.edu/~gmark/chi08-mark.pdf">23 minutes to regain focus</a> after an interruption. When CI breaks your flow three times a day, you&#39;re not losing 20 minutes per build. You&#39;re losing 20 minutes of waiting plus 23 minutes getting back into flow state. <a href="https://www.apa.org/research/action/multitask">Task switching reduces productivity by up to 40%</a>. The actual cost isn&#39;t the wait time. It&#39;s the shattered attention, the broken flow states, the mental fatigue from constant context switching. That 60 minutes of visible waiting becomes 2+ hours of lost productivity.  </p>
</blockquote>
<p>
<strong>The typical sequence looks like this:</strong></p>
<p>
<strong>Year 1: Faster Hardware.</strong> Team hits slow CI times. Leadership approves €300K annually for the fastest runners available. CI time drops from 20 minutes to 12 minutes. Modest improvement. Everyone celebrates. But wait times per developer only drop from 60 to 36 minutes per day. The team is still building and testing everything, just slightly faster. Value unlocked: roughly 2 FTE worth of time (€280K). But it costs €300K per year. You&#39;re barely breaking even.</p>
<p>
<strong>Year 2: Hire More People.</strong> Throughput is still terrible. Leadership hires 10 more developers at €1.4M annual cost. But more developers means more CI contention, longer queues, more conflicts. Wait times actually increase to 75 minutes per day. Instead of gaining capacity, you&#39;ve made the problem worse. The coordination overhead grows faster than the output.</p>
<p>
<strong>Year 3: Technology Rewrite.</strong> Someone suggests rewriting everything in React Native. &quot;No compile times!&quot; The rewrite takes six months, costs the entire team&#39;s focus, and millions in opportunity cost. At the end, you&#39;ve traded one set of problems for another. The coordination problems are identical. They just happen in a different language.</p>
<p>
<strong>Total spend over three years:</strong> €3M+ in direct costs (hardware, new hires, rewrite), plus countless hours of engineering time. Throughput improved marginally.</p>
<p>
<strong>The alternative sequence that actually works:</strong></p>
<p>
<strong>Month 1:</strong> Implement <a href="https://docs.tuist.dev/en/guides/features/cache">binary caching</a> and <a href="https://docs.tuist.dev/en/guides/features/selective-testing">selective testing</a>. When a developer changes one module, the others use cached builds. When someone touches code, only the affected tests run, not the entire suite.</p>
<p>
<strong>The result:</strong> CI time drops from 20 minutes to 4 minutes. Wait times drop from 60 to 12 minutes per developer per day. That&#39;s 48 minutes saved per developer per day. Across 30 developers, you&#39;ve saved 4 FTE worth of time annually. At €140K average salary, that&#39;s €560K in recovered value. The cost? Roughly €20K per year. Not by building faster, but by building less. Only what changed. Only what matters.</p>
<h2 id="the-choice" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Choice<a href="#the-choice" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Choice"></a></h2>
<p>
This story is every company&#39;s story. The only question is which chapter you&#39;re in, and whether you&#39;ll choose to optimize the right thing.</p>
<p>
The difference isn&#39;t just the value, though that&#39;s dramatic. The difference is that one approach treats symptoms while the other fixes the disease. Faster hardware makes waste happen faster. More people amplify coordination overhead. Better workflows eliminate the waste entirely.</p>
<p>
Optimize workflows before hardware. A faster machine makes your waste happen faster. A better workflow eliminates the waste. One costs significantly more and provides modest improvements. The other costs a fraction and transforms the organization.</p>
<p>
Ready to see what this looks like for your team? <a href="https://cal.tuist.dev/team/tuist/tuist?overlayCalendar=true">Talk to us</a> about how Tuist can help you scale, or <a href="https://tuist.dev/users/register">get started</a> and see the difference in days, not months.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Designing the new marketing site ]]></title>
      
      
      <author>
        <name><![CDATA[  Asmit Malakannawar  ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Unveiling the new Tuist website, and a behind-the-scenes look at our evolution from a CLI-only tool to an all-in-one platform for app development. ]]></summary>
      <link href="https://tuist.dev/blog/2025/11/03/website-redesign"/>
      <id>https://tuist.dev/blog/2025/11/03/website-redesign</id>
      <updated>Mon, 03 Nov 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist&#39;s website is where developers begin exploring the product, learning about its features, and discovering what Tuist is all about. We wanted to make this experience simple and welcoming, not just visually, but also in how the brand and content feel.</p>
<p>
As Tuist evolved, the old website no longer represented what we’re building and shipping today. After <a href="https://tuist.dev/blog/2025/04/17/meet-new-tuist">redesigning our developer dashboard</a>, we wanted our landing page to match its new look and feel. We began by reviewing what worked well on the previous site and what could be improved, drawing inspiration from other developer tools. We also realized some important information was missing, and with new features launching every cycle, it felt like the perfect time for a redesign.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/home-page.png" alt="Home page of the new marketing site">
</p>
<h2 id="the-process" tabindex="-1" class="marketing__blog_post__body__content__heading">
The process<a href="#the-process" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The process"></a></h2>
<p>
Before redesigning the website, we spent time researching what could be improved and what was missing. We reviewed over 25 developer tool websites, studying their strengths and weaknesses. The website plays a big role in shaping our brand identity, and with the dashboard redesign, we wanted to bring the same look and feel to our site.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/moodboard.png" alt="Website moodboard">
</p>
<p>
The main issues we identified were:</p>
<ul>
  <li>
The old website didn’t clearly communicate that Tuist had grown beyond the CLI.  </li>
  <li>
The previous site layout made it hard to find information or understand Tuist’s features.  </li>
  <li>
It was difficult to showcase new features and updates effectively.  </li>
  <li>
We weren’t clearly demonstrating how Tuist supports real teams or inspire new contributors to get involved.  </li>
  <li>
The website visuals didn’t align with the newly redesigned dashboard.  </li>
</ul>
<h3 id="stage-1:-clarifying-the-message" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stage 1: Clarifying the Message<a href="#stage-1:-clarifying-the-message" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stage 1: Clarifying the Message"></a></h3>
<p>
The first thing we noticed was that our story wasn’t being told the way we wanted. Tuist had grown far beyond being just a CLI tool, yet our website still gave that impression. We wanted to communicate what Tuist truly is today, a platform that helps teams build, collaborate, and ship mobile apps.</p>
<p>
To do this, we reworked the content and page flow to focus on the bigger picture of Tuist’s ecosystem. We looked at developer tools like <a href="https://vercel.com/home">Vercel</a>, <a href="https://supabase.com/">Supabase</a>, and <a href="https://linear.app/homepage">Linear</a>, understanding how they convey complex ideas in a clear, simple way. More on this topic below.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/headers.png" alt="Website header exploration">
</p>
<h3 id="stage-2:-improving-the-structure-and-navigation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stage 2: Improving the Structure and Navigation<a href="#stage-2:-improving-the-structure-and-navigation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stage 2: Improving the Structure and Navigation"></a></h3>
<p>
Another issue we saw was how difficult it was to understand what Tuist offered at a glance. The navigation felt fragmented and didn’t guide new visitors through the story.
We decided to rebuild the site structure with clarity in mind, making it easy for developers to discover what Tuist does, explore its features, and understand how it can help their teams. Now the navigation is divided into three main parts: Features, Developers, and Resources, each designed to provide clarity on a specific aspect of Tuist.</p>
<ul>
  <li>
<strong>Features</strong> highlights what Tuist offers, showcasing key capabilities and how they help teams build and scale Xcode projects efficiently.  </li>
  <li>
<strong>Developers</strong> puts the focus on the community, open-source contributions, documentation, and ways to get involved.  </li>
  <li>
<strong>Resources</strong> brings together learning materials, blog posts, and guides to help both new and experienced users make the most out of Tuist.   </li>
</ul>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/navigation.png" alt="Navigation menus">
</p>
<h3 id="stage-3:-enhancing-visual-storytelling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stage 3: Enhancing Visual Storytelling<a href="#stage-3:-enhancing-visual-storytelling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stage 3: Enhancing Visual Storytelling"></a></h3>
<p>
Our previous design made it hard to showcase Tuist’s features, especially as we kept releasing new ones. Updating the website each time felt limited due to the old design system. To make this process smoother and more engaging, we introduced bento card designs, modular sections paired with custom illustrations that explain each feature visually. This made it much easier to highlight what’s new, while also giving the page a more dynamic and consistent feel. This is my favorite part of the entire website!</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/bento-cards.png" alt="Tuist feature bento cards">
</p>
<h3 id="stage-4:-showcasing-customer-stories-and-community-impact" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stage 4: Showcasing Customer Stories and Community Impact<a href="#stage-4:-showcasing-customer-stories-and-community-impact" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stage 4: Showcasing Customer Stories and Community Impact"></a></h3>
<p>
Being an open-source first company, we’ve always valued transparency and community involvement. But the old site didn’t really show how Tuist was helping teams or how contributors were shaping the project. </p>
<p>
We added customer case studies with custom illustrations to tell real stories, how teams reduced build times, improved collaboration, and scaled their development workflows using Tuist. </p>
<p>
We also introduced community metrics to highlight our open-source growth and inspire more developers to contribute.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/case-studies.png" alt="Customer case study cards">
</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/stats.png" alt="Stats for Tuist project">
</p>
<h3 id="stage-5:-unifying-the-brand-and-visual-language" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stage 5: Unifying the Brand and Visual Language<a href="#stage-5:-unifying-the-brand-and-visual-language" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stage 5: Unifying the Brand and Visual Language"></a></h3>
<p>
Finally, we wanted to make sure our website felt like a natural extension of our newly redesigned dashboard. The previous site had a different tone and visual style, which made the overall experience feel disconnected. We brought everything together under a unified brand identity and built the website using the <a href="https://github.com/tuist/noora">Noora Design System</a>. All core elements, buttons, input fields, shadows, colors, and variables, are based on Noora for consistency and scalability.</p>
<p>
While the foundation remains the same, we introduced and customized several components specifically for the website, such as blog post cards, header background visuals, and the overall gradient-driven style. You can think of it as a more stylized, marketing-focused version of Noora. Even the custom illustrations were designed using Noora’s color variables to keep everything visually cohesive.</p>
<p>
This consistency not only strengthened how Tuist looked but also how it felt to use and explore.</p>
<h2 id="iterating-on-the-perfect-first-impression" tabindex="-1" class="marketing__blog_post__body__content__heading">
Iterating on the Perfect First Impression<a href="#iterating-on-the-perfect-first-impression" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Iterating on the Perfect First Impression"></a></h2>
<p>
One of the biggest hurdles in the redesign was getting the <strong>header illustration</strong> just right. It plays a huge role in shaping the first impression, but representing the tool’s value in one illustration is quite challenging.</p>
<p>
At first, we tried using a simple <strong>dashboard screenshot</strong>, but that approach quickly proved impractical. We release new features frequently, and updating the image every time would be too time-consuming. On top of that, a static dashboard screenshot doesn’t communicate much value to new users who are unfamiliar with the product.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/first-version.png" alt="First version of Tuist landing page">
</p>
<p>
Next, we experimented with a <strong>CLI animation</strong>, but it didn’t quite fit. Tuist has grown far beyond the CLI, and focusing on it wouldn’t convey the story we wanted to tell about how fast the product is evolving.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/second-version.png" alt="Second version of Tuist landing page">
</p>
<p>
We then explored a concept featuring <strong>interactive charts and graphs</strong>, complete with animated team cursors to visualize collaboration. Although this version looked interesting in tests, we realized that random charts and metrics wouldn’t mean much to someone visiting the site for the first time.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/third-version.png" alt="Third version of Tuist landing page">
</p>
<p>
Finally, we landed on the current version, one that centers around the <strong>mobile development experience</strong>, highlighting key features we’re proud of, such as <strong>reducing build times</strong>, <strong>skipping repetitive tests</strong>, and <strong>automated QA testing</strong>. This version feels true to what Tuist is today and communicates our message clearly.</p>
<p>
  <img src="/marketing/images/blog/2025/11/03/website-redesign/final-version.png" alt="Final version of Tuist landing page">
</p>
<p>
As Tuist continues to grow, we expect the header to evolve as well, after all, it’s the first impression any developer gets when they land on our page.</p>
<h2 id="what’s-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next<a href="#what’s-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next"></a></h2>
<p>
Design is never truly done. It’s a constant process of refinement and exploration. While dark mode is definitely something we’ve been thinking about (and it’s on the list), our minds are already moving toward what’s next, experimenting with new visual patterns, micro-interactions, and immersive storytelling elements that make the experience feel more alive.</p>
<p>
We see Tuist’s design language as something that will evolve with the product, adapting to how developers use it, and reflecting the balance between engineering precision and creative expression.</p>
<p>
If we had to describe it in one line: we’re building something functional, but with soul. Redesigning and redefining Tuist’s message was and will continue being a fun and rewarding process.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Organize your targets with metadata tags ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Discover how metadata tags help you organize modules across multiple dimensions and focus development with module caching. ]]></summary>
      <link href="https://tuist.dev/blog/2025/10/31/metadata-tags"/>
      <id>https://tuist.dev/blog/2025/10/31/metadata-tags</id>
      <updated>Fri, 31 Oct 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
As codebases grow, organizing modules becomes increasingly complex. Teams typically structure their code using familiar patterns: grouping modules by architectural layers (UI, business logic, data), by features (authentication, payments, settings), by team ownership, or by platform. These organizational patterns help maintain clarity as projects scale from a handful of modules to dozens or hundreds.</p>
<p>
Traditionally, teams have used Xcode&#39;s building blocks like projects, targets, and schemes to model these organizational patterns. A project might contain all networking-related modules, another might house the UI layer, and so on. This approach works, but it has a fundamental limitation: it forces you to choose a single organizational dimension. If you organize by layer, you lose visibility into features. If you organize by feature, you obscure the architectural structure.</p>
<p>
The reality is that organizational needs are often orthogonal to each other. The networking layer crosses multiple features. A single feature might span multiple architectural layers. A team might own modules across different parts of the system. Xcode&#39;s project-based organization cannot easily represent these intersecting concerns.</p>
<h2 id="enter-metadata-tags" tabindex="-1" class="marketing__blog_post__body__content__heading">
Enter metadata tags<a href="#enter-metadata-tags" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Enter metadata tags"></a></h2>
<p>
This is precisely the problem that metadata tags solve, and it is one of Tuist&#39;s most powerful yet underutilized features. Metadata tags are simple string labels that you attach to targets in your project manifests. They allow you to organize modules across multiple dimensions simultaneously without restructuring your codebase or creating complex Xcode project hierarchies.</p>
<p>
Here is a practical example:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let project = Project(
    name: &quot;MyApp&quot;,
    targets: [
        .target(
            name: &quot;NetworkKit&quot;,
            destinations: .iOS,
            product: .framework,
            bundleId: &quot;com.example.networkkit&quot;,
            sources: [&quot;Sources/**&quot;],
            metadata: .metadata(tags: [
                &quot;layer:networking&quot;,
                &quot;team:platform&quot;,
                &quot;feature:core&quot;
            ])
        ),
        .target(
            name: &quot;PaymentUI&quot;,
            destinations: .iOS,
            product: .framework,
            bundleId: &quot;com.example.paymentui&quot;,
            sources: [&quot;Sources/**&quot;],
            metadata: .metadata(tags: [
                &quot;layer:ui&quot;,
                &quot;team:commerce&quot;,
                &quot;feature:payment&quot;
            ])
        )
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
Notice how each target can have multiple tags representing different organizational dimensions. <code class="inline">NetworkKit</code> is simultaneously part of the networking layer, owned by the platform team, and considered core functionality. This multi-dimensional organization is impossible to represent with traditional Xcode project structures.</p>
<h2 id="tag-naming-conventions" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tag naming conventions<a href="#tag-naming-conventions" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tag naming conventions"></a></h2>
<p>
While you can use any string as a tag, following a consistent naming convention makes your tags more maintainable and discoverable. We recommend using prefixes to namespace your tags by dimension:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Organize by architectural layer
metadata: .metadata(tags: [&quot;layer:ui&quot;, &quot;layer:business&quot;, &quot;layer:data&quot;])

// Organize by team ownership
metadata: .metadata(tags: [&quot;team:platform&quot;, &quot;team:commerce&quot;, &quot;team:identity&quot;])

// Organize by feature area
metadata: .metadata(tags: [&quot;feature:authentication&quot;, &quot;feature:payment&quot;, &quot;feature:settings&quot;])

// Organize by platform
metadata: .metadata(tags: [&quot;platform:ios&quot;, &quot;platform:macos&quot;, &quot;platform:watchos&quot;])    </shiki-highlight>
  </div>
</div>
<p>
You can combine multiple dimensions on a single target, creating a rich metadata system that reflects the true complexity of your codebase without adding structural overhead.</p>
<h2 id="focusing-your-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Focusing your development<a href="#focusing-your-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Focusing your development"></a></h2>
<p>
Once you have tagged your targets, you can use these tags to focus your development workflow. Here&#39;s a quick walkthrough showing how this works in practice:</p>
<iframe title="Product Walkthroughs - Group your targets by tags" width="560" height="315" src="https://videos.tuist.dev/videos/embed/vfhqz7P1JbDw2tk97aUGVe" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<p>
Want to work exclusively on the networking layer? Simply generate a focused workspace:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate tag:layer:networking    </shiki-highlight>
  </div>
</div>
<p>
Tuist will generate a workspace that includes all targets tagged with <code class="inline">layer:networking</code>, plus their dependencies. This gives you a smaller, more manageable workspace that contains only what you need for your current work.</p>
<p>
You can also combine tags with target names:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Focus on the Payment feature
tuist generate tag:feature:payment

# Focus on all commerce team modules
tuist generate tag:team:commerce

# Focus on a specific target by name
tuist generate PaymentUI    </shiki-highlight>
  </div>
</div>
<p>
When you focus on targets, Tuist automatically includes:</p>
<ul>
  <li>
All targets matching your query  </li>
  <li>
All dependencies of those targets  </li>
  <li>
Test targets for the focused targets  </li>
</ul>
<p>
Everything else is excluded, giving you faster project loading, quicker indexing, and more focused development.</p>
<h2 id="the-real-power:-combining-tags-with-module-caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
The real power: combining tags with module caching<a href="#the-real-power:-combining-tags-with-module-caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The real power: combining tags with module caching"></a></h2>
<p>
This is where metadata tags truly shine. Tuist&#39;s module caching can replace targets with their precompiled <code class="inline">.xcframework</code> binaries, dramatically speeding up build times. When you combine this with metadata tags, you get fine-grained control over which parts of your codebase remain as editable source and which are replaced with binaries.</p>
<p>
Here is a concrete example. Imagine you are working on the networking layer of your app. You want to iterate quickly on networking code, but you do not need to touch any UI or business logic. With metadata tags and module caching, you can do this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Warm the cache with all compiled binaries
tuist cache

# Generate a project focused on networking, keeping those targets as sources
tuist generate tag:layer:networking    </shiki-highlight>
  </div>
</div>
<p>
Tuist will generate a workspace where:</p>
<ul>
  <li>
All targets tagged with <code class="inline">layer:networking</code> remain as editable source code  </li>
  <li>
All dependencies of those targets that are not tagged with <code class="inline">layer:networking</code> are replaced with cached binaries  </li>
  <li>
You get full compile-time feedback on your networking changes  </li>
  <li>
But you avoid recompiling unrelated parts of the codebase  </li>
</ul>
<p>
This workflow is transformative for large codebases. A one-line change in a low-level module traditionally forces a full rebuild. With focused caching through metadata tags, you recompile only what matters for your current work.</p>
<p>
Let&#39;s look at a more complex scenario. Suppose you are on the commerce team working on payment features. Your workspace might look like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Focus on commerce team modules, everything else is cached
tuist generate tag:team:commerce    </shiki-highlight>
  </div>
</div>
<p>
Now only your team&#39;s modules compile from source. All platform infrastructure, other features, and shared utilities? Cached binaries. You get instant feedback on your team&#39;s code without waiting for the entire codebase to compile.</p>
<p>
Or perhaps you want to work across features but only at the UI layer:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Keep all UI layer modules as sources
tuist generate tag:layer:ui    </shiki-highlight>
  </div>
</div>
<p>
Now you can freely modify UI components across different features, while the business logic and data layers are served from cache.</p>
<h2 id="practical-examples" tabindex="-1" class="marketing__blog_post__body__content__heading">
Practical examples<a href="#practical-examples" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Practical examples"></a></h2>
<p>
Let&#39;s walk through some real-world scenarios to illustrate how teams can leverage metadata tags.</p>
<h3 id="scenario-1:-feature-team-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Scenario 1: Feature team development<a href="#scenario-1:-feature-team-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Scenario 1: Feature team development"></a></h3>
<p>
Your app has multiple features: authentication, payments, settings, and analytics. Each is owned by a different team. You tag your modules accordingly:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Authentication modules
.target(
    name: &quot;AuthenticationKit&quot;,
    metadata: .metadata(tags: [&quot;feature:auth&quot;, &quot;team:identity&quot;, &quot;layer:business&quot;])
)
.target(
    name: &quot;AuthenticationUI&quot;,
    metadata: .metadata(tags: [&quot;feature:auth&quot;, &quot;team:identity&quot;, &quot;layer:ui&quot;])
)

// Payment modules
.target(
    name: &quot;PaymentKit&quot;,
    metadata: .metadata(tags: [&quot;feature:payment&quot;, &quot;team:commerce&quot;, &quot;layer:business&quot;])
)
.target(
    name: &quot;PaymentUI&quot;,
    metadata: .metadata(tags: [&quot;feature:payment&quot;, &quot;team:commerce&quot;, &quot;layer:ui&quot;])
)    </shiki-highlight>
  </div>
</div>
<p>
A developer on the commerce team runs:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate tag:team:commerce    </shiki-highlight>
  </div>
</div>
<p>
They get a workspace with <code class="inline">PaymentKit</code> and <code class="inline">PaymentUI</code> as sources, everything else cached. The workspace loads faster, Xcode indexes less code, and clean builds are dramatically faster because most of the app is precompiled.</p>
<h3 id="scenario-2:-architectural-layer-refactoring" tabindex="-1" class="marketing__blog_post__body__content__heading">
Scenario 2: Architectural layer refactoring<a href="#scenario-2:-architectural-layer-refactoring" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Scenario 2: Architectural layer refactoring"></a></h3>
<p>
Your team is refactoring the data layer to use a new database framework. You want to work on data layer modules without touching business logic or UI:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate tag:layer:data    </shiki-highlight>
  </div>
</div>
<p>
All data layer modules remain as sources. Business logic and UI layers are cached binaries. You can iterate rapidly on your database code, running tests frequently without waiting for unrelated code to compile.</p>
<h3 id="scenario-3:-platform-infrastructure-work" tabindex="-1" class="marketing__blog_post__body__content__heading">
Scenario 3: Platform infrastructure work<a href="#scenario-3:-platform-infrastructure-work" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Scenario 3: Platform infrastructure work"></a></h3>
<p>
You are working on core infrastructure that many features depend on: networking, logging, analytics. These modules are tagged as platform team ownership:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate tag:team:platform    </shiki-highlight>
  </div>
</div>
<p>
You get all platform infrastructure as sources, allowing you to make changes across multiple infrastructure modules simultaneously, while feature code remains cached.</p>
<h3 id="scenario-4:-multi-platform-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Scenario 4: Multi-platform development<a href="#scenario-4:-multi-platform-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Scenario 4: Multi-platform development"></a></h3>
<p>
Your codebase supports iOS, macOS, and watchOS. You are working exclusively on the watchOS app:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate tag:platform:watchos    </shiki-highlight>
  </div>
</div>
<p>
Only watchOS-specific code and its direct dependencies remain as sources. iOS and macOS modules? Cached. You avoid the cognitive load and compile time of irrelevant platforms.</p>
<h2 id="standardizing-tags-with-helpers" tabindex="-1" class="marketing__blog_post__body__content__heading">
Standardizing tags with helpers<a href="#standardizing-tags-with-helpers" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Standardizing tags with helpers"></a></h2>
<p>
As your tagging strategy matures, you will want consistency across your project manifests. <a href="https://docs.tuist.dev/en/guides/features/projects/code-sharing">Project description helpers</a> provide a perfect way to standardize tag application:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Tuist/ProjectDescriptionHelpers/Target+Templates.swift
import ProjectDescription

extension Target {
    public static func feature(
        name: String,
        team: String,
        layer: String,
        dependencies: [TargetDependency] = []
    ) -&gt; Target {
        .target(
            name: name,
            destinations: .iOS,
            product: .framework,
            bundleId: &quot;com.example.\(name.lowercased())&quot;,
            sources: [&quot;Sources/**&quot;],
            dependencies: dependencies,
            metadata: .metadata(tags: [
                &quot;feature:\(name.lowercased())&quot;,
                &quot;team:\(team.lowercased())&quot;,
                &quot;layer:\(layer.lowercased())&quot;
            ])
        )
    }
}    </shiki-highlight>
  </div>
</div>
<p>
Now in your manifests, you can use this helper to ensure consistent tagging:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project(
    name: &quot;Features&quot;,
    targets: [
        .feature(name: &quot;Authentication&quot;, team: &quot;Identity&quot;, layer: &quot;Business&quot;),
        .feature(name: &quot;Payment&quot;, team: &quot;Commerce&quot;, layer: &quot;Business&quot;),
        .feature(name: &quot;Settings&quot;, team: &quot;Platform&quot;, layer: &quot;UI&quot;)
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
This approach ensures every module gets tagged consistently, making your organization system reliable and maintainable as your team grows.</p>
<h3 id="organizing-tags-with-enums" tabindex="-1" class="marketing__blog_post__body__content__heading">
Organizing tags with enums<a href="#organizing-tags-with-enums" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Organizing tags with enums"></a></h3>
<p>
For even better maintainability and compile-time safety, you can define your tags as constants organized in enum namespaces. This prevents typos and makes it easy to discover available tags:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Tuist/ProjectDescriptionHelpers/Tags.swift
import ProjectDescription

public enum Tags {
    // Using enums as namespaces for string constants
    public enum Domain {
        public static let authentication = &quot;domain:authentication&quot;
        public static let payment = &quot;domain:payment&quot;
        public static let settings = &quot;domain:settings&quot;
        public static let networking = &quot;domain:networking&quot;
    }

    public enum Layer {
        public static let ui = &quot;layer:ui&quot;
        public static let business = &quot;layer:business&quot;
        public static let data = &quot;layer:data&quot;
    }

    public enum Team {
        public static let identity = &quot;team:identity&quot;
        public static let commerce = &quot;team:commerce&quot;
        public static let platform = &quot;team:platform&quot;
    }

    public enum Platform {
        public static let ios = &quot;platform:ios&quot;
        public static let macos = &quot;platform:macos&quot;
        public static let watchos = &quot;platform:watchos&quot;
    }
}    </shiki-highlight>
  </div>
</div>
<p>
Note that these are enums used as namespaces containing static string properties, not enum cases. When you access <code class="inline">Tags.Domain.authentication</code>, you get the string <code class="inline">&quot;domain:authentication&quot;</code> directly.</p>
<p>
Then use these constants in your target definitions:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Tuist/ProjectDescriptionHelpers/Target+Templates.swift
import ProjectDescription

extension Target {
    public static func feature(
        name: String,
        domain: String,
        team: String,
        layer: String,
        dependencies: [TargetDependency] = []
    ) -&gt; Target {
        .target(
            name: name,
            destinations: .iOS,
            product: .framework,
            bundleId: &quot;com.example.\(name.lowercased())&quot;,
            sources: [&quot;Sources/**&quot;],
            dependencies: dependencies,
            metadata: .metadata(tags: [domain, team, layer])
        )
    }
}    </shiki-highlight>
  </div>
</div>
<p>
And in your manifests:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project(
    name: &quot;Features&quot;,
    targets: [
        .feature(
            name: &quot;AuthenticationKit&quot;,
            domain: Tags.Domain.authentication,
            team: Tags.Team.identity,
            layer: Tags.Layer.business
        ),
        .feature(
            name: &quot;PaymentUI&quot;,
            domain: Tags.Domain.payment,
            team: Tags.Team.commerce,
            layer: Tags.Layer.ui
        )
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
This approach provides:</p>
<ul>
  <li>
<strong>Autocomplete</strong> - Your IDE suggests available tags as you type  </li>
  <li>
<strong>Refactoring safety</strong> - Renaming a tag updates all usages  </li>
  <li>
<strong>No typos</strong> - The compiler catches invalid tag references  </li>
  <li>
<strong>Discoverability</strong> - New team members can explore available tags through IDE completion  </li>
</ul>
<p>
You can extend this pattern further with methods that return computed tags:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
public enum Tags {
    public enum Feature {
        public static func name(_ value: String) -&gt; String {
            &quot;feature:\(value.lowercased())&quot;
        }
    }
}

// Usage
metadata: .metadata(tags: [Tags.Feature.name(&quot;Authentication&quot;)])    </shiki-highlight>
  </div>
</div>
<p>
This gives you the flexibility to generate tags dynamically while still maintaining organization and type safety.</p>
<h2 id="best-practices" tabindex="-1" class="marketing__blog_post__body__content__heading">
Best practices<a href="#best-practices" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Best practices"></a></h2>
<p>
Based on our experience helping teams adopt metadata tags, here are some recommendations:</p>
<p>
<strong>Start simple.</strong> Begin with a single tagging dimension that solves your most pressing organizational problem. If your biggest pain point is architectural clarity, start with layer tags. If it is team boundaries, start with team tags. You can always add more dimensions later.</p>
<p>
<strong>Be consistent.</strong> Use the same naming conventions across all manifests. Document your tagging strategy in your project&#39;s README so everyone understands the system.</p>
<p>
<strong>Use helpers.</strong> Leverage project description helpers to enforce consistency. This prevents typos and ensures new modules get tagged correctly from the start.</p>
<p>
<strong>Iterate based on workflow.</strong> Pay attention to which tags you actually use for focusing. If you rarely use certain tags, consider whether they are adding value or just noise.</p>
<p>
<strong>Review periodically.</strong> As your project evolves, review your tagging strategy. Teams reorganize, features mature, and architectural patterns change. Keep your tags current.</p>
<h2 id="why-this-matters" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why this matters<a href="#why-this-matters" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why this matters"></a></h2>
<p>
Metadata tags might seem like a simple feature, but they unlock a fundamentally different way of working with large codebases. Instead of fighting against monolithic builds or creating complex Xcode workspace hierarchies, you can organize your code conceptually and generate focused workspaces on demand.</p>
<p>
When combined with module caching, this becomes even more powerful. You get the benefits of modularization, fast compilation times, and the flexibility to work on any part of your codebase without waiting for irrelevant modules to compile.</p>
<p>
If you have been using Tuist but have not yet explored metadata tags, we strongly encourage you to try them. They represent a different paradigm for organizing and working with Xcode projects, one that scales naturally as your project grows.</p>
<p>
To learn more about metadata tags, check out our <a href="https://docs.tuist.dev/en/guides/features/projects/metadata-tags">documentation</a>. You can also explore how tags integrate with <a href="https://docs.tuist.dev/en/guides/features/cache/module-cache">module caching</a> to supercharge your development workflow.</p>
<p>
We would love to hear how you are using metadata tags. Share your experiences in our <a href="https://community.tuist.dev/">community forum</a>, <a href="https://slack.tuist.dev/">Slack</a>, or on <a href="https://fosstodon.org/@tuist">Mastodon</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Speed up your builds with the remote Tuist cache for Xcode ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn how the Xcode compilation cache works and how Tuist shares it to cut build times in local and CI environments ]]></summary>
      <link href="https://tuist.dev/blog/2025/10/22/xcode-cache"/>
      <id>https://tuist.dev/blog/2025/10/22/xcode-cache</id>
      <updated>Wed, 22 Oct 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<a href="https://www.swift.org">Swift</a> is an amazing and modern programming language. It&#39;s also a language that&#39;s statically typed, allowing the compiler to highlight issues before an application is even run. And the earlier in the development process an issue is detected, the easier it typically is to fix. But statically typed languages come at a cost – and that is build time. Ever since the migration from Objective-C, this has been a sore point of the language. And while the compiler and the hardware have both improved over the years, they haven&#39;t been able to keep up with the pace of growth of Swift codebases. A problem more acute with the broader usage of AI agents, like <a href="https://openai.com/codex/">Codex</a> or <a href="https://www.claude.com/product/claude-code">Claude Code</a>, leading to even more Swift code being written.</p>
<p>
This sometimes leads to drastic choices being made by iOS engineering teams, such as moving to other build systems like <a href="https://bazel.build/">Bazel</a> that has a great support for caching or completely abstracting away the platform with technologies like <a href="https://reactnative.dev/">React Native</a>. We&#39;ve developed our own solution to help teams with their build times by leveraging generation to cache modules as <code class="inline">.xcframework</code>s. And we believe that, at the time of writing, the Tuist module cache is still the best solution for iOS teams looking to speed up their builds.</p>
<p>
However, now you can <strong>improve your incremental and clean build times in just a couple of minutes</strong>, regardless of your Xcode setup, with the <strong>new Xcode compilation cache</strong> <a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-26-release-notes#New-Features">introduced in Xcode 26</a>.</p>
<iframe title="Get started with the Tuist cache for Xcode" width="560" height="315" src="https://videos.tuist.dev/videos/embed/ewgDzSbw5DojtpUHqk6hxP" style="border: 0px;" allow="fullscreen" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h3 id="how-is-this-different-than-derived-data" tabindex="-1" class="marketing__blog_post__body__content__heading">
How is this different than derived data<a href="#how-is-this-different-than-derived-data" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How is this different than derived data"></a></h3>
<p>
You might be wondering how the new Xcode compilation cache is different than derived data. </p>
<p>
Build artifacts in the derived data directory are stored in a location-based structure. When Xcode builds your project, it places compiled objects, indexes, and intermediate build products in paths tied to your project&#39;s location and configuration. On the surface, this seems reasonable-put the outputs next to the inputs. But this seemingly simple design decision has created a cascade of problems as our development workflows have evolved.</p>
<p>
Consider a typical scenario: you&#39;re working on a feature branch, building and testing locally. Your colleague in another time zone is working on a different feature. Your CI system is running builds for every pull request. All of you are compiling the same dependencies-maybe a large framework like <a href="https://github.com/Alamofire/Alamofire">Alamofire</a> or a set of internal modules that rarely change. Yet each of you is doing this work independently, from scratch, because derived data can&#39;t safely share these artifacts.</p>
<p>
Why not? The problems run deep:</p>
<p>
<strong>Non-deterministic builds</strong>: The same source code compiled on different machines or in different locations can produce different artifacts. This isn&#39;t just theoretical-debug symbols contain absolute paths, frameworks reference their build location, and various metadata gets embedded during compilation. If you build on your MacBook Pro and I build on my Mac Studio, we get different bytes, even though the source code is identical. This makes caching across environments fragile at best and incorrect at worst.</p>
<p>
<strong>Path dependencies</strong>: Artifacts often contain hardcoded absolute paths. Your framework compiled at <code class="inline">/Users/you/Projects/App</code> doesn&#39;t work when I try to use it at <code class="inline">/Users/me/Code/App</code>. These path references break when moved between machines or when the project is located in different directories. It&#39;s not just about where the framework is-it&#39;s about where it was built, where its dependencies were, where the SDK is installed. It&#39;s turtles all the way down.</p>
<p>
<strong>Coarse invalidation</strong>: When something goes wrong-and something always eventually goes wrong-developers resort to deleting the entire derived data directory. Hours of compilation work, discarded in seconds, because there&#39;s no reliable way to determine which artifacts are still valid and which are corrupted or stale. We throw away the good with the bad because we can&#39;t tell them apart.</p>
<p>
<strong>Limited sharing</strong>: These characteristics combine to make it nearly impossible to reliably share build artifacts across team members or between local development and CI environments. Some teams have tried-setting up shared network drives, syncing derived data directories, elaborate rsync scripts. These approaches are fragile and often cause more problems than they solve. The fundamental architecture just wasn&#39;t designed for this use case.</p>
<h3 id="moving-beyond-derived-data:-xcode-compilation-cache" tabindex="-1" class="marketing__blog_post__body__content__heading">
Moving beyond derived data: Xcode compilation cache<a href="#moving-beyond-derived-data:-xcode-compilation-cache" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Moving beyond derived data: Xcode compilation cache"></a></h3>
<p>
All of these problems are solved by the new Xcode compilation cache which, in many ways, is similar to other performant build systems like the already-mentioned Bazel or <a href="https://gradle.com">Gradle</a>. These build systems and now the Xcode compilation cache use a combination of a <a href="https://en.wikipedia.org/wiki/Key%E2%80%93value_database">key value store</a> (also known as action cache) and a <a href="https://en.wikipedia.org/wiki/Content-addressable_storage">content-addressable storage</a> (commonly referred to as CAS).</p>
<p>
When the build system compiles your app, instead of storing artifacts based on file paths, it computes a <a href="https://bazel.build/basics/hermeticity">hermetic</a> fingerprint for each build action and stores the compilation artifacts in the content-addressable storage where each artifact is identified by a unique digest of the contents. This makes builds deterministic, portable, and more efficient.</p>
<p>
This shift has taken Apple multiple years to execute – the first RFC to add support for caching using the content-addressable storage in the LLVM project (which the Swift build system builds upon) <a href="https://discourse.llvm.org/t/rfc-add-an-llvm-cas-library-and-experiment-with-fine-grained-caching-for-builds/59864">was proposed in 2022</a>. But since Xcode 26, you can enable the Xcode compilation cache by setting the <code class="inline">COMPILATION_CACHE_ENABLE_CACHING</code> to <code class="inline">YES</code> in your build settings or in the <code class="inline">xcodebuild</code> invocation and reap the benefits – at least locally.</p>
<h3 id="sharing-cache-across-environments" tabindex="-1" class="marketing__blog_post__body__content__heading">
Sharing cache across environments<a href="#sharing-cache-across-environments" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Sharing cache across environments"></a></h3>
<p>
Improving local incremental builds is already a huge improvement to our daily Swift development. But since the new compilation cache is <em>portable</em>, shouldn&#39;t we be able to reuse build artifacts from the CI on our local machines? Or between individual CI runs? Can we finally stop rebuilding the same code over and over again?</p>
<p>
You might wonder if you can cache the whole compilation cache across CI runs and then download the whole directory to your local machines – and while you <em>can</em>, this directory will be continuously growing and there&#39;s no direct way to tell which artifacts are still actively being used and which not.</p>
<p>
Instead, the build system uses a <a href="https://github.com/swiftlang/llvm-project/tree/d7ed79de3369c94f62f25fb48fbfcfbf152ae350/llvm/lib/RemoteCachingService/RemoteCacheProto">gRPC contract</a> to communicate with external services. Whenever the build system needs to look up a value in the key-value store or the content-addressable storage, if it&#39;s not found in the local compilation cache, it will connect to the remote service, if available, and attempt to retrieve the missing data from there. Similarly, when storing new artifacts, the build system will store them both in locally and remotely.</p>
<p>
So, how do you get started with remote caching using Tuist?</p>
<ol>
  <li>
Install the <a href="https://tuist.io/docs/getting-started/installation/">Tuist CLI</a> if you haven&#39;t already.  </li>
  <li>
Integrate your project with Tuist by running <code class="inline">tuist init</code>.  </li>
  <li>
Run <code class="inline">tuist setup cache</code>.  </li>
</ol>
<p>
The <code class="inline">tuist setup cache</code> then lists out the build settings that you need to configure in your project:</p>
<ul>
  <li>
<code class="inline">COMPILATION_CACHE_ENABLE_CACHING=YES</code> to enable local or remote caching
-<code class="inline">COMPILATION_CACHE_ENABLE_PLUGIN=YES</code> to enable a plugin that communicates with the remote cache  </li>
  <li>
<code class="inline">COMPILATION_CACHE_REMOTE_SERVICE_PATH=$HOME/.local/state/tuist/your-organization-handle_your-project-handle.sock</code> to instruct plugin where it can find the gRPC socket proxy  </li>
</ul>
<p>
The gRPC socket proxy acts as a bridge between the build system and needs to be running as a daemon in your system. Note that <code class="inline">tuist setup cache</code> will automatically start the gRPC socket proxy for you.</p>
<h3 id="the-xcode-compilation-cache-in-the-real-world" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Xcode compilation cache in the real world<a href="#the-xcode-compilation-cache-in-the-real-world" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Xcode compilation cache in the real world"></a></h3>
<p>
Let&#39;s take a look at how the Xcode compilation cache helps to reduce build times in real world projects. We&#39;ve benchmarked the performance of the Xcode compilation cache in the following projects:</p>
<ul>
  <li>
<a href="https://github.com/Automattic/pocket-casts-ios/">Pocket Casts</a>  </li>
  <li>
<a href="https://github.com/wikipedia/wikipedia-ios">Wikipedia</a>  </li>
  <li>
<a href="https://github.com/tuist/tuist">Tuist CLI</a>  </li>
</ul>
<p>
<strong>Note:</strong> The following benchmarks were conducted on <a href="https://namespace.so/">Namespace</a> M4 Pro runners on 20th and 21st October 2025 using Xcode 26.0.1. All benchmark results are available in our <a href="https://github.com/tuist/cache-benchmark">cache-benchmark</a> repository.</p>
<p>
Here&#39;s what we&#39;ve found:</p>
<img alt="Benchmark compilation cache results" src="/marketing/images/blog/2025/10/22/xcode-cache/benchmark.png">
<p>
For Wikipedia, the build time was reduced by 24% when using the local cache (simulating clean builds with local compilation cache already populated) and by 18% when using the remote cache (simulating clean builds with remote, not local, compilation cache already populated). For Pocket Casts, the build times were reduced by 36% for the local cache and by 20% for the remote cache.</p>
<p>
We&#39;ve observed the biggest improvement in build times for Tuist CLI, where the build time was reduced by 77% when using the local cache and by 53% when using the remote cache. Why is the cache so much faster against the Tuist CLI project? We&#39;ll need to talk about the current state of the cache.</p>
<h3 id="not-everything-is-cacheable-(yet)" tabindex="-1" class="marketing__blog_post__body__content__heading">
Not everything is cacheable (yet)<a href="#not-everything-is-cacheable-(yet)" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Not everything is cacheable (yet)"></a></h3>
<p>
The compilation cache is still an early, opt-in feature. In the latest Xcode release (26.0.1), there are still a lot of tasks that are <em>not</em> cacheable, like computing the build graph or compiling parts of Swift packages. This is why the Tuist CLI performs better than other projects because we integrate our packages as <a href="https://docs.tuist.dev/en/guides/features/projects/dependencies#xcodeprojcodified-graphs">Xcode projects</a>. In fact, we&#39;ve also measured the performance of the cache against Mastodon – in one case using the default SwiftPM integration, in the other generating those dependencies as Xcode projects. The difference was significant:</p>
<img alt="Benchmark compilation cache results" src="/marketing/images/blog/2025/10/22/xcode-cache/mastodon-benchmark.png">
<p>
Whereas building Mastodon with the local cache and the remote cache with the default SwiftPM integration improved the build by 19% and 30%, respectively, the improvements were 55% and 69% for the Mastodon project generated with Tuist.</p>
<p>
We certainly expect the types of tasks that Xcode can cache to expand, including a better support for Swift packages, but it&#39;s important to highlight the current limitations of the cache.</p>
<h3 id="latency-is-key" tabindex="-1" class="marketing__blog_post__body__content__heading">
Latency is key<a href="#latency-is-key" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Latency is key"></a></h3>
<p>
Apart from a difference between generated and non-generated projects, you might have also noticed that the remote cache is typically slower than the local cache – and that will always be the case as file operations are faster than going over the network–because physics. The build system is making thousands or tens of thousands of requests per build and each request has a cost associated with it.</p>
<p>
This is why we&#39;re investing heavily in our edge infrastructure to minimize that cost and serve the cache requests at the minimum latency. We&#39;re also exploring the possibility of pushing the edge concept into our customers&#39; offices-deploying cache nodes on local networks to improve the latency even further. And we expect that Apple will invest more into optimizing the distributed cache, such as by computing which artifacts will be needed during the build earlier and prefetching them.</p>
<h3 id="the-power-of-module-based-caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
The power of module-based caching<a href="#the-power-of-module-based-caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The power of module-based caching"></a></h3>
<p>
While Apple continues to invest into the build caching, we&#39;ve already iterated on <a href="https://docs.tuist.dev/en/guides/develop/build/cache">module-based binary caching</a> over the years and based on our <a href="https://github.com/tuist/cache-benchmark">benchmarks</a>, our approach currently <strong>outperforms</strong> the remote cache – achieving better or similar build times (including generation and fetching of binaries) as the <em>local</em> compilation cache. Instead of caching individual compilation units, we cache entire frameworks and libraries, pre-fetch them before generating the project and then letting the build system compile only what has changed. This also has the side effect that Xcode projects are leaner and Xcode is faster.</p>
<p>
And the combination of both approaches can achieve even greater improvements. Xcode compilation cache provides a more granular level caching that works seamlessly with Xcode, while module-based caching delivers the coarse-grained reuse that dramatically cuts build times in modular architectures.</p>
<h3 id="looking-ahead" tabindex="-1" class="marketing__blog_post__body__content__heading">
Looking ahead<a href="#looking-ahead" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Looking ahead"></a></h3>
<p>
If you&#39;ve been intrigued, head over to our <a href="https://docs.tuist.dev/en/guides/features/cache">documentation</a> to get started with the Tuist cache. We&#39;re currently offering the remote Xcode cache <strong>for free</strong> while we iterate on the integration of this feature with pricing being announced later in the year. In the meantime, we will continue to improve the latency and introduce detailed analytics to help you understand the impact of the cache on your build times. You can already leverage our <a href="https://docs.tuist.dev/en/guides/features/insights#builds">build insights</a> to track the build performance in both local and CI environments.</p>
<p>
And if you have any questions or feedback, reach out to us <a href="https://community.tuist.dev/">in our  community forum</a>, <a href="https://slack.tuist.dev/">Slack</a> or send me a mail directly at <a href="mailto:marek@tuist.dev">marek@tuist.dev</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Why Large Swift Projects Hit a Wall (And How to Break Through) ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Large Swift codebases hit walls: slow builds, flaky tests, complex graphs. We dive into why Apple's toolchain struggles at scale and how teams can overcome these challenges without React Native or Bazel. ]]></summary>
      <link href="https://tuist.dev/blog/2025/09/22/scale"/>
      <id>https://tuist.dev/blog/2025/09/22/scale</id>
      <updated>Mon, 22 Sep 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
It&#39;s 2025, and developing Swift apps at a certain scale continues to be a challenge. If you are just getting started, or your project is just growing in code volume, number of modules, or number of developers contributing to it, you might not feel the need to make any changes to your setup. But if your codebase has a decent size, you are likely running into issues here and there that degrade your productivity and your motivation to contribute new features to an app. At Tuist, we see that every day.</p>
<p>
We see many large organizations showing up seeking support, and many developers who, having experienced the support that Tuist gives them, don&#39;t think twice when they start new projects and bet on Tuist from the get-go.</p>
<p>
In this post, I&#39;d like to discuss the common challenges that we continue to see and how Tuist helps you overcome them. I&#39;ll also acknowledge some of the work that <a href="https://apple.com">Apple</a> has done and is doing to improve the state of things, and hopefully leave you informed about the many things you likely suffer from but can&#39;t pinpoint to the root cause. But before we dive into the details, let&#39;s first talk about what I like to call the wake-up leadership crisis.</p>
<h2 id="wake-up-leadership-crisis" tabindex="-1" class="marketing__blog_post__body__content__heading">
Wake-Up Leadership Crisis<a href="#wake-up-leadership-crisis" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Wake-Up Leadership Crisis"></a></h2>
<p>
Apps usually are just another interface for the users or customers of a business to interact with the business domain, and a business&#39;s ultimate goal is to increase revenue and profit. If they move in competitive markets, <strong>this requires them to move at a faster pace, and this often leads to tension in iOS development teams where, regardless of how many human resources you throw at the problem, the bottleneck is the toolchain and everything that surrounds it.</strong> Your build times of 2 minutes or CI time of 5 years ago have become 30, and there&#39;s no Apple Silicon that can take those 30 back down to 2 minutes. And it doesn&#39;t matter how much blame you place on Apple—business doesn&#39;t care about that or about how much you&#39;ve normalized those times. They deem it unacceptable, especially when they have other platforms like the web with much faster and more advanced tooling that gives them not only the speed they need but also visibility into what&#39;s happening to optimize the setup.</p>
<p>
Having reached that point, we often see companies taking a few paths. One of the most common is adopting <a href="https://reactnative.dev/">React Native</a>. They throw a JS runtime into the mix, which allows them to hot-reload changes in development and even distribute updates and fixes over the air. Shopify <a href="https://shopify.engineering/five-years-of-react-native-at-shopify">migrated all their mobile apps to React Native</a> for this exact reason. They had invested in <a href="https://react.dev/">React</a> prior to this decision, and it made sense for them because it would also align mobile with the mental model they were already familiar with on the web. But you need to be mindful of the trade-off you are making here. By choosing React Native, you are abstracting away the native platform, and this comes at a cost that you can absorb yourself, as was the case with Shopify by assembling a team to develop and maintain foundational pieces, or rely on companies like <a href="https://expo.dev/">Expo</a> that package an ecosystem of libraries and services under an umbrella.</p>
<p>
The second path that we see some companies taking is <a href="https://bazel.build/">Bazel</a>. Bazel is a very advanced and powerful build system. But replacing an entire build system is often even costlier than introducing React Native. Most programming languages and ecosystems come with some build system built-in: <a href="https://elixir-lang.org/">Elixir</a>, <a href="https://www.swift.org/">Swift</a>, Xcode, <a href="https://gradle.org/">Gradle</a>, <a href="https://doc.rust-lang.org/cargo/">Cargo</a>... So when you replace it with something else, reconciling the build system piece with everything that builds upon it is a huge investment that not many companies are willing to make. At Tuist, we often see companies whose story goes like this: One or a few engineers get excited about Bazel, they convince leadership to spend a few months of work introducing Bazel, they manage to get it working although no one knows how it works except them, those engineers leave the company, and the company decides to drop Bazel because it&#39;s too costly. We&#39;ve seen countless companies going through this path, and I completely get it. As much as you can, you should stay close to your build system because that also means staying close to the ecosystem that surrounds it.</p>
<p>
For those who prefer to stay closer to the native toolchain and therefore have a lower cost to scale up their development, they see Tuist as the best option. This is by design. <strong>We abstracted just where we had to, such that we helped teams overcome the challenges while keeping an eye on and peeling abstractions when the issues were addressed at the right layer, like we saw with Xcode 16 and the introduction of <a href="https://dimillian.medium.com/why-you-should-use-xcode-16-buildable-folders-instead-of-groups-6f438611914d">buildable folders</a>.</strong></p>
<p>
At this point, you might wonder: what are those challenges that large companies are facing, and that I might face too, if not today, maybe tomorrow? Let&#39;s explore some of them.</p>
<h2 id="1.-modularization" tabindex="-1" class="marketing__blog_post__body__content__heading">
1. Modularization<a href="#1.-modularization" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 1. Modularization"></a></h2>
<p>
Modularization is not just a tool for defining boundaries between components. It&#39;s also a tool to access reusable pieces of code across repositories and to share code between an app and the extensions contained in it. It&#39;s something that we&#39;ll do sooner or later. Modularization sadly comes at a cost, also related to an Xcode design decision.</p>
<p>
As you might know, binaries can be linked statically or dynamically. Static linking happens at build time, while dynamic linking happens at runtime. The decision of one or the other for each module in the graph has implications that expand beyond just setting the linking type. For example, dynamic modules need to be explicitly copied into the right product so the linker can find them. Or static libraries will have to be linked from certain products that can link static libraries, ensuring we don&#39;t end up with duplicated symbols. <strong>Doing these things right is easy if there are a few modules in the graph, but as it grows in complexity, no human brain can hold a graph in memory to set things up and fix issues when they arise.</strong></p>
<p>
As with derived data, people feel this pain. And the pain was so strong that they decided <a href="https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/">SwiftPM</a> would be the best solution to alleviate the pain. &quot;These people have solved defining modules, so they must have figured out how to reconcile a SwiftPM&#39;s graph into an Xcode project&#39;s,&quot; the community must have thought. So without planning it, Apple found itself reconciling a SwiftPM graph with an Xcode project&#39;s graph, which might also contain dependencies that are implicitly defined. What a fun challenge that must have been for Apple. And if that wasn&#39;t challenging enough, they added an extra variable to make it even more challenging: <a href="https://developer.apple.com/documentation/xcode/configuring-your-project-to-use-mergeable-libraries">mergeable libraries</a>.</p>
<p>
Over the past years, we&#39;ve seen more and more companies outsourcing graph complexity to SwiftPM, just to realize soon after that they had to trade developer ergonomics to reduce the complexity of maintaining a graph. Now projects are resolved asynchronously, at times that you can&#39;t control, and a project that used to be ready to compile at launch no longer is because now it&#39;s invoking a SwiftPM process in the background whose process needs to be reconciled with Xcode&#39;s legacy business logic and UI. Fun, fun.</p>
<blockquote>
  <p>
We&#39;ve seen more and more companies outsourcing graph complexity to SwiftPM, just to realize soon after that they had to trade developer ergonomics to reduce the complexity of maintaining a graph  </p>
</blockquote>
<p>
This is a complicated topic to bring into a discussion because one of the reasons why this happens is Swift itself and Package.swift manifests, which have to be compiled. Some of which can contain implicit side effects that they can&#39;t know but assume exist, as the pulling of sub-modules automatically shows. It&#39;s amazing writing manifests in Swift—Tuist does that, too—but when it comes at the cost of degrading the developer experience at a certain scale, I wonder if that&#39;s a good idea. For comparison, Cargo, Rust&#39;s build system, uses serializable .toml files. The JavaScript ecosystem uses .json, and Bazel uses the <a href="https://github.com/bazelbuild/starlark">Starlark</a> language, which is domain-specific and optimized for build systems.</p>
<p>
For Tuist, making modularization extremely simple was our main goal, along with avoiding frequent git conflicts, from the get-go. It was the thing that set us apart from other generation tools and also the foundation that we needed to optimize teams&#39; projects. I might be biased here, but Tuist is the best modularization tool out there. SwiftPM was designed for resolving dependencies, does a decent job at that, and should remain as a tool for that. <strong>Xcode projects should evolve to ease modularization such that SwiftPM is not used as a project manager.</strong> This is a symptom that Xcode and Xcode projects require a design iteration. Until then, I think <a href="https://docs.tuist.dev/en/guides/features/projects">generating projects</a> like Tuist does is the best path forward. Anything required to get the linking right, from build phases to build settings, is all taken care of for you, such that you can focus on the graph structure and not on the implementation details that make it possible within an Xcode project.</p>
<h2 id="2.-build-times" tabindex="-1" class="marketing__blog_post__body__content__heading">
2. Build Times<a href="#2.-build-times" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2. Build Times"></a></h2>
<p>
Every new year, new Apple Silicon comes out, and your managers rush to put a case to leadership to buy them because they might help make a cut in the build times of your projects. But the cuts got smaller and smaller over time. Justifying the investment got harder and harder over time, and you need an alternative. Unfortunately, React Native and Bazel are not an option, and sadly, Xcode doesn&#39;t help you with that.</p>
<p>
This is the main driver of organizations adopting Tuist. They want their build times to be faster. Depending on whom you ask what &quot;slow&quot; is, you get different answers, but we&#39;ve seen them ranging from &quot;I&#39;m tired of my 5-minute builds&quot; to &quot;I&#39;m tired of my 2-hour builds on CI.&quot; <strong>Those times have been terribly normalized in the ecosystem.</strong> And they get worse when people clean derived data to mitigate an Xcode issue that they don&#39;t understand. &quot;Can&#39;t they multi-task?&quot; you might wonder. As if multi-tasking is the answer to everything. Multi-tasking means context-switching, and context-switching is terribly expensive too.</p>
<p>
Soon after having made modularization easier with generated projects, we noticed we had the right foundation to optimize build times, learning from projects like <a href="https://github.com/Carthage/Carthage">Carthage</a> or Bazel, and mutating the graph to incorporate binaries in it and ensuring our generation logic would reconcile all the changes. The result? A caching system that helps teams achieve up to 80% improvements (e.g. <a href="/blog/2024/12/16/trendyol">Trendyol achieved 65%</a>) in their build times. The effectiveness depends strongly on the modularization and how the contributions distribute across all the modules. At the very least, you&#39;ll get all your third-party dependencies cached. <em>Because who wants to be compiling code that you barely change on clean builds?</em></p>
<p>
You can check out <a href="https://tuist.dev/tuist/tuist">Tuist&#39;s public dashboard</a> to see how our current cache effectiveness moves around 84%. Or take, for example, this <a href="https://tuist.dev/tuist/tuist/runs/019970ac-6e19-7015-a5b0-0c979b70a669?tab=compilation-optimizations">test run</a> where 122 modules were replaced with binaries. We hope that caching will eventually come natively to the native build system, and CAS is the right step in that direction. At Tuist, we are preparing for that by building the fastest and lowest-latency solution so that people can plug their Xcode projects in the near future without any hassle.</p>
<h2 id="3.-test-times" tabindex="-1" class="marketing__blog_post__body__content__heading">
3. Test Times<a href="#3.-test-times" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 3. Test Times"></a></h2>
<p>
Building is just part of what teams do after changes are implemented. They also need to run tests. Locally, developers usually run the tests that have changed or those that are connected with the file changes. However, on CI, teams commonly run all the tests of the test suite. And this means that <strong>the more tests they add, the slower they&#39;ll take to run on CI, and at some point, you&#39;ll have to do something about it.</strong></p>
<p>
We touched on some strategies <a href="/blog/2025/03/25/tests">here</a>, but the general idea is that you should first consider parallelizing within the environment, since CI environments give you access to all the Apple Silicon cores. This comes with the challenge of ensuring your code is designed for parallelization, which is often not the case, manifesting as race conditions that appear as flakiness or, even worse, data races. If that&#39;s not enough, you can then parallelize across environments, but this requires doing some sort of sharding of tests across environments and playing with the <code class="inline">-build-for-testing</code> and <code class="inline">-test-without-building</code> flags. Sharding is something we plan to solve at Tuist such that developers can automatically do it by using flags with the CLI instead of having to write their own script. If this is not enough, the last thing that you can do is test selection, which consists of selecting the tests that should run based on the file changes.</p>
<p>
At Tuist, we provide <a href="https://docs.tuist.dev/en/guides/features/selective-testing">selective testing</a>, which works both with generated projects and vanilla Xcode projects and makes use of our fingerprinting logic that&#39;s Git-agnostic and has been battle-tested by many large organizations with complex Xcode projects. The adoption is quite straightforward:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist xcodebuild test -workspace App.xcworkspace -scheme App
# Instead of
xcodebuild test -workspace App.xcworkspace -scheme App    </shiki-highlight>
  </div>
</div>
<h2 id="4.-insights" tabindex="-1" class="marketing__blog_post__body__content__heading">
4. Insights<a href="#4.-insights" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 4. Insights"></a></h2>
<p>
You build or run tests in your Xcode project, Xcode&#39;s UI presents you with the result, and that data remains there, in your environment, as if nothing happened, until you accidentally clean it with your deletion of derived data. Things look no different on CI. Your builds run, and the output from your builds is two things: whether it passed or not and xcodebuild&#39;s logs, often formatted using formatting tools like <a href="https://github.com/cpisciotta/xcbeautify">xcbeautify</a>. The isolation and ephemeral character of that information prevent the big picture that teams need to answer these questions: Are my builds getting faster or slower? And what about my tests? Is my app growing in size? Are there any new flaky tests? In other ecosystems like the web, collecting, processing, storing, and analyzing data is a common practice. In Apple&#39;s, it&#39;s not, despite its importance in making informed decisions to improve the development setup.</p>
<p>
As for the reasons for this not being that common, I have a few guesses. The first one is that the data exported by Apple&#39;s toolchain is very proprietary, which adds an extra level of indirection requiring some processing pipeline before the data can be exported to systems to analyze it. The <code class="inline">.xcresult</code> and <code class="inline">.xcactivitylog</code> are good examples of that. That was never data designed to be consumed outside of Xcode and therefore lacks documentation and the tools to process it. The second reason I believe is that storing the data requires a database, which in some cases might need to be more than just a standard SQL database—for example, <a href="https://clickhouse.com/">ClickHouse</a>—and a server that can authenticate and authorize access to the database. These are systems that, first, iOS teams don&#39;t usually have the familiarity with and the eagerness to build and maintain, and second, struggle to get leadership&#39;s support to do. Therefore, they end up with this being a hobby project within the company that often takes the shape of tinkering with Swift in the server environment. It&#39;s impressive what teams out there have been able to build, but it&#39;s not enough.</p>
<p>
For data to be useful, you also need to present it in a way that&#39;s useful. You also need to correlate data to derive new useful information. And also build a system such that you can define tripwires and help teams monitor if things don&#39;t go as planned. It&#39;s a lot. And this is what we are building with Tuist such that the leadership of those companies can outsource that to Tuist and let their engineering resources be focused on building the apps. You can check out our read-only public <a href="https://tuist.dev/tuist/tuist">Tuist</a> dashboard to get a sense of the data that you&#39;d be able to get for your teams. For example, with one <a href="https://videos.tuist.dev/w/mWM5SfMEwMSuRyKZu1rPmG">scheme post action</a>, you can get build insights in the dashboard, and soon you&#39;ll be able to do the same with your test results.</p>
<p>
You can continue working blindly, and you might go a long way with it, but without data, you&#39;ll have a hard time having conversations with your leadership, especially when times like &quot;I&#39;ve heard of React Native; what do you think?&quot; come.</p>
<h2 id="5.-derived-data" tabindex="-1" class="marketing__blog_post__body__content__heading">
5. Derived Data<a href="#5.-derived-data" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 5. Derived Data"></a></h2>
<p>
Who doesn&#39;t know <a href="https://medium.com/@alaxhenry0121/what-is-xcode-deriveddata-complete-guide-for-ios-developers-in-2025-5f962e402fab">derived data</a>? That folder that everyone deletes when compilation fails. The same folder whose deletion leads to a clean build, which can be quite slow in some cases. Derived data proved to be a bad decision whose effects are felt in the long run. A decision that has made many projects in the wild compile not because they are explicitly importing dependencies, but because they can accidentally find them in derived data. Implicit imports can lead to editor features such as macro expansions or Swift previews working unreliably because the editor resolves an invalid graph, causing missing binaries to be absent in derived data for those editor features to work. As crazy as it sounds, it&#39;s all rooted in derived data, but we don&#39;t talk much about it—not enough, in my opinion. <strong>We joke about previews not working or cleaning derived data here and there, but the problem is indeed serious.</strong></p>
<p>
The good news is that Apple is aware of it and is working on it through a different approach called <a href="https://github.com/swiftlang/swift-build/tree/main/Sources/SWBCAS">content-addressable store (CAS)</a> and <a href="https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies">explicit modules</a>, which they are gently pushing people toward. So instead of having one shared directory, the build system uses hashes to look up compilation artifacts from previous compilations and uses them instead of invoking the compiler. This works in cases where your project has no implicit dependencies. And here&#39;s the thing: rolling out such a system requires Apple not only to introduce explicit modules but also to nudge the ecosystem to adopt them. In my opinion, the push has been too gentle and lacked a bit of the &quot;why it&#39;s needed.&quot; Perhaps because doing so requires acknowledging a past design decision that led to derived data becoming a problem. I think it&#39;s fine. <strong>I&#39;d rather see Apple being open and transparent about it and how they are approaching it than discussing it internally and leaving us making the connections between some Xcode features and the reasons why they might be introducing them.</strong></p>
<p>
<a href="https://docs.tuist.dev/en/guides/features/projects">Tuist-generated projects</a> can&#39;t prevent implicit dependencies, but the explicitness of declaring dependencies makes them a bit less likely. Because of that, we introduced a <a href="https://docs.tuist.dev/en/cli/inspect/implicit-imports">command</a> that developers can run against their generated projects to check for implicit imports using static code analysis, and this is something I strongly recommend to everyone.</p>
<p>
As I mentioned earlier, my bet is that <strong>the reliability of many Xcode features is strongly correlated with the explicitness of the project&#39;s graph, so the less implicitness you have, the better.</strong> Sadly, this is not evangelized enough, neither by Apple nor by the community, so it often feels like sending messages into the void.</p>
<h2 id="closing-thoughts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing Thoughts<a href="#closing-thoughts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing Thoughts"></a></h2>
<p>
At Tuist, we are building the native platform for scaling Swift app development so that you don&#39;t have to. There are problems that are on Apple to solve, and we are excited to see them implicitly acknowledging some of them and throwing some resources at them. And there are other problems that require some awareness first from your side, and this is what we aim to create with these posts, and solutions like Tuist that take some of the burden off your plate such that adopting them is just one line of code in your project, instead of having to maintain a complex system.</p>
<p>
These solutions happen to make any agentic coding experience even better, because at the end of the day, any pain experienced by humans will be more annoying through agents. From slow feedback loops in compilations to lack of information to inform the coding sessions. That&#39;s why we deem crucial in the platform that we are building explicitness and openness of the data that we are working with such that agents have access to it at any time.</p>
<p>
Scaling Swift app development happened to be the challenge we got obsessed with and that we continue to be excited about. If any of the challenges resonated with you and you&#39;d like to share them with us, send us an email at contact@tuist.dev and let&#39;s chat. We are here to help any organization out there because we want organizations to be more effective at their missions.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist's AI whitepaper ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ AI is revolutionizing how we build Apple apps. We're pioneering agentic coding, Tuist QA (automated QA testing), instant previews, and data accessibility to make Swift development dramatically faster and more accessible. ]]></summary>
      <link href="https://tuist.dev/blog/2025/08/11/tuist-ai-whitepaper"/>
      <id>https://tuist.dev/blog/2025/08/11/tuist-ai-whitepaper</id>
      <updated>Mon, 11 Aug 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
AI is reshaping software development at an unprecedented pace, breaking through limitations that once seemed insurmountable. For Apple developers, this transformation presents unique opportunities and challenges within a platform known for its sophisticated but often opaque tooling.</p>
<p>
At Tuist, we&#39;ve been deeply immersed in exploring how AI can transform the Apple development experience. Through continuous experimentation and community collaboration, we&#39;re building bridges between cutting-edge AI capabilities and the realities of Swift and Xcode development.</p>
<p>
Inspired by <a href="https://penpot.app/blog/penpot-ai-whitepaper/">Penpot&#39;s thoughtful AI whitepaper</a>, this document shares our vision for AI&#39;s role in Apple development. We&#39;re taking a pragmatic, incremental approach that enhances rather than replaces existing workflows, working with Apple&#39;s tools to unlock new possibilities while respecting the platform&#39;s unique constraints and opportunities.</p>
<h2 id="building-the-foundation-for-agentic-coding" tabindex="-1" class="marketing__blog_post__body__content__heading">
Building the foundation for agentic coding<a href="#building-the-foundation-for-agentic-coding" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Building the foundation for agentic coding"></a></h2>
<p>
Since Tuist&#39;s inception, we&#39;ve tackled the most frustrating aspects of Apple development—from decoding <a href="https://github.com/tuist/xcodeproj/">Xcode&#39;s proprietary project formats</a> to revolutionizing build times through intelligent binary caching. These improvements aren&#39;t just quality-of-life enhancements; they&#39;re essential infrastructure for the AI-powered future of development.</p>
<p>
Here&#39;s the critical insight: the same pain points that frustrate human developers completely break agentic coding experiences. When an AI agent modifies your SwiftUI view, it needs immediate feedback—not a 5-minute incremental build that might fail mysteriously. When it refactors your networking layer, it needs to verify the changes instantly, not wait for a full app rebuild and simulator launch.</p>
<p>
Agents need fast feedback from multiple sources: the build system, running applications, live previews, and more. Some information can be collected because it exists in the system and either the model has learned about it or accesses it through <a href="https://modelcontextprotocol.io/docs/getting-started/intro">Model Context Protocols (MCPs)</a>. However, agents often lack access to crucial information, such as SwiftUI preview trees resolved at runtime or how the build system processes graphs to generate artifacts.</p>
<p>
Some improvements remain outside our direct control, such as enhancing framework documentation, minimizing major Swift changes, or Apple decoupling Xcode&#39;s layers and providing programmatic APIs for extension. Whether these changes occur likely depends on Apple&#39;s willingness to trust their developer community beyond just app creation to include tool enhancement.</p>
<p>
The community is actively bridging the gap between agents and official tools. This includes <a href="https://github.com/giginet/xcodeproj-mcp-server">MCPs that expose CRUD APIs for Xcode projects</a> and solutions that approximate hot-reloading workflows by managing xcodebuild and simulator tools. Until underlying tools provide better APIs and documentation, these translations remain essential.</p>
<p>
This brings us to our role. As mentioned earlier, shortening feedback loops is crucial, and we believe this should be our primary contribution. Today, this means binary caching based on project generation, but in the future, when caching is built into the build system, we&#39;re working toward creating the fastest, lowest-latency cache solution that agents can access regardless of their location.</p>
<p>
Imagine an edge-accelerated Xcode build cache that makes compilation virtually instantaneous, regardless of project size or location. We&#39;re building the infrastructure that enables both agents and developers to iterate at the speed of thought. Every build generates rich diagnostic data streamed to <a href="https://clickhouse.com/">ClickHouse</a>, providing immediate insights when things go wrong—because agents need to understand failures just as much as successes.</p>
<h2 id="autonomous-qa:-testing-at-the-speed-of-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Autonomous QA: Testing at the speed of development<a href="#autonomous-qa:-testing-at-the-speed-of-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Autonomous QA: Testing at the speed of development"></a></h2>
<p>
The traditional testing pyramid is being turned upside down. While unit tests remain valuable, the real game-changer is automated acceptance testing—the kind that actually validates user experiences but has historically been too expensive to maintain.</p>
<p>
Consider the current reality: a developer submits a PR, waits for CI, gets feedback hours later, context switches are everywhere. Now imagine this: an AI agent reviews your code, spins up a preview, tests it like a real user would, and provides comprehensive feedback—all within minutes of pushing your changes.</p>
<p>
Acceptance tests are expensive to develop because they require learning imperative interfaces for UI interaction through accessibility APIs. Moreover, the contract and use case being tested often remain implicit, making tests fragile and difficult to fix when they break. While Xcode 26 reduces the cost of writing these tests, it addresses only part of the challenge.</p>
<p>
An alternative is QA testing, but this approach is equally or more expensive. Human testers are costly, and the process doesn&#39;t scale effectively. As variability increases, scenarios multiply, and QA teams often end up testing less critical scenarios because they lack business context to prioritize effectively. When issues arise, the diagnostic information they provide is limited—typically written reports and screenshots without logs, network requests, or database and keychain state information. This leads to significant developer time spent on QA interactions.</p>
<p>
Consequently, many companies rely solely on unit tests and solid architecture to prevent certain issues, but this approach cannot catch all scenarios. While no solution is perfect, we believe you can approximate comprehensive testing with minimal cost.</p>
<p>
<strong>We&#39;re making this a reality with <a href="https://community.tuist.dev/t/taking-tuist-qa-to-the-next-level/710/2">Tuist QA</a>.</strong> Our AI agents don&#39;t just run test scripts—they interact with your app like actual users. They understand context from your PR description, explore edge cases based on code changes, and provide detailed reports with screenshots, logs, and actionable insights.</p>
<p>
Here&#39;s how it works: mention <code class="inline">@tuist-qa</code> in your PR, and within minutes, an agent spins up a macOS environment, installs your app, and methodically tests the changes. It reads your <code class="inline">QA.md</code> for context, understands your app&#39;s architecture, and focuses testing on what matters most.</p>
<p>
All the necessary components for agentic QA are already in place: Tuist supports <a href="https://docs.tuist.dev/en/guides/features/previews">previews</a> for app bundle uploads with commit and branch tracking, and it integrates with GitHub for event-driven actions. Additionally, integration with Namespace is being built for spinning up macOS environments where agents can operate. Early results are promising.</p>
<p>
You mention us in a PR, and we respond shortly after with a summary and link to a detailed testing report that includes logs, screenshots, and all necessary diagnostic information. We gather context from PRs and other sources, such as <code class="inline">QA.md</code> files.</p>
<p>
Instead of developing and maintaining expensive acceptance test suites, you can simply tag us to test work, and we handle the rest.</p>
<h2 id="instant-previews:-share-work-in-seconds,-not-hours" tabindex="-1" class="marketing__blog_post__body__content__heading">
Instant previews: Share work in seconds, not hours<a href="#instant-previews:-share-work-in-seconds,-not-hours" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Instant previews: Share work in seconds, not hours"></a></h2>
<p>
In an AI-accelerated development cycle, the ability to instantly share and test changes becomes critical. Traditional preview distribution is broken—it takes hours to get a testable build to stakeholders, and by then, the context is lost.</p>
<p>
The fundamental problem? Apple&#39;s code signing. Current solutions force you to pre-sign apps for specific devices, meaning every new tester requires a pipeline re-run. Enterprise certificates help but come with their own limitations and costs.</p>
<p>
<strong>We&#39;re solving this with on-demand signing.</strong> Instead of signing at build time, we sign at install time—specifically for each device. This means:</p>
<ul>
  <li>
Push code, get a preview link immediately  </li>
  <li>
Anyone in your organization can install with one tap  </li>
  <li>
Automatic certificate management  </li>
  <li>
Feedback flows directly back to your PR or Slack  </li>
</ul>
<p>
The future we&#39;re building: An agent completes a feature, generates a preview, and your entire team is testing it within seconds. Product managers provide feedback that agents immediately incorporate. The development cycle compresses from days to hours.</p>
<p>
We&#39;ll also build an SDK that collects feedback and forwards it to places where agents can access context, whether Slack channels or GitHub PRs. If we develop an alternative experience for idea ignition, you&#39;ll have a &quot;share&quot; button that completes with &quot;here&#39;s your link, share it with the world&quot;—because that&#39;s how we believe developer experience should work.</p>
<h2 id="unlocking-apple's-black-box:-data-accessibility-for-ai" tabindex="-1" class="marketing__blog_post__body__content__heading">
Unlocking Apple&#39;s black box: Data accessibility for AI<a href="#unlocking-apple's-black-box:-data-accessibility-for-ai" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Unlocking Apple's black box: Data accessibility for AI"></a></h2>
<p>
Apple&#39;s development ecosystem is notoriously opaque. Build logs are binary, project formats are undocumented, and runtime behavior is largely invisible. This opacity becomes a critical bottleneck when AI agents need to understand what&#39;s happening in your codebase.</p>
<p>
We&#39;re systematically breaking down these barriers:</p>
<ul>
  <li>
<strong>Build insights</strong>: We parse <code class="inline">.xcactivitylog</code> files to extract compilation times, bottlenecks, and failure patterns  </li>
  <li>
<strong>Bundle analysis</strong>: <a href="https://github.com/tuist/Rosalind">Rosalind</a> transforms binary artifacts into queryable schemas  </li>
  <li>
<strong>Test intelligence</strong>: Real-time analysis of test execution, flakiness patterns, and coverage gaps  </li>
  <li>
<strong>Runtime telemetry</strong>: Capturing and structuring app behavior data for agent consumption  </li>
</ul>
<p>
If you&#39;ve used tools like <a href="https://www.anthropic.com/claude-code">Claude Code</a>, you&#39;ve likely noticed it knows how to interface with GitHub CLI to view PR comments and address them. GitHub provides data and makes it accessible through CLI for agent consumption. We&#39;re adopting a similar approach, where agents can plan work by examining flaky tests in test suites or optimize project build parallelization by analyzing project graphs and build result data.</p>
<p>
As mentioned earlier, since these formats and internal layers are designed to feed upper internal layers rather than external tools that could enhance development experience, Apple may be hesitant to expose them. Opening these systems might enable ecosystem development around alternative coding experiences, as we&#39;re seeing with increased Cursor adoption for iOS development. While we believe such openness would be hugely beneficial, Apple&#39;s approach continues to evolve in interesting ways that suggest growing openness to developer tool innovation.</p>
<h2 id="from-idea-to-app:-exploring-rapid-materialization" tabindex="-1" class="marketing__blog_post__body__content__heading">
From idea to app: Exploring rapid materialization<a href="#from-idea-to-app:-exploring-rapid-materialization" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to From idea to app: Exploring rapid materialization"></a></h2>
<p>
Every great app starts as a spark of inspiration—a &quot;what if&quot; moment that demands exploration. But the path from idea to working prototype is often where that spark dies, buried under setup complexity, build configurations, and distribution friction.</p>
<p>
The industry is attacking this problem from multiple angles. <a href="https://vibetunnel.sh/">VibeTunnel</a> validated that developers want to continue development remotely or on the go. Meanwhile, tools like <a href="https://lovable.dev/">Lovable</a> and <a href="https://v0.dev/">V0</a> are presenting hosted, conversational no-code-like solutions that enable rapid prototyping through natural language. But Apple development presents unique challenges: native capabilities are essential, but the platform&#39;s controlled distribution creates inherent friction.</p>
<p>
We&#39;re exploring this frontier with <a href="https://github.com/tuist/ignite">Ignite</a>, our experiment in zero-friction prototyping:</p>
<ul>
  <li>
<strong>Instant setup</strong>: No Xcode projects, no configurations—just start coding  </li>
  <li>
<strong>Live preview</strong>: Changes reflect immediately in your browser  </li>
  <li>
<strong>Develop anywhere</strong>: Continue building from any device, anytime, without local setup  </li>
  <li>
<strong>Native bridge</strong>: Access platform capabilities without leaving the rapid iteration loop  </li>
</ul>
<p>
This isn&#39;t about replacing native development—it&#39;s about creating the fastest possible path from idea to validation. Once you know something works, our infrastructure helps you graduate to a full native implementation with proper testing, distribution, and all the platform capabilities you need.</p>
<p>
Importantly, we&#39;re holding to see how this space evolves. The rapid pace of change means what seems promising today might be obsolete tomorrow. We recognize that full agentic coding solutions are massive undertakings better suited to generic players in the space. Our approach is more measured—we&#39;re interested in how our specific strengths in caching, build optimization, and the Apple ecosystem can contribute to lowering the barriers to idea exploration.</p>
<p>
Some of this work is already happening through our existing infrastructure. Our binary caching reduces build times, our preview system enables rapid sharing, and our data accessibility efforts provide the context agents need. Each improvement reduces the incremental cost of exploration, which increases our appetite to continue investing in this direction—but always with a focus on what uniquely benefits Apple developers.</p>
<h2 id="the-journey-ahead" tabindex="-1" class="marketing__blog_post__body__content__heading">
The journey ahead<a href="#the-journey-ahead" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The journey ahead"></a></h2>
<p>
What dominates discussions today may be obsolete tomorrow. The pace of change in this space is extraordinary, which is why we approach these ideas with an exploratory mindset, discussing and refining them weekly as a team. We remain open-minded in some areas while focusing our energy where we see solid opportunities, like Tuist QA.</p>
<p>
Moreover, some problems like coding can be well-addressed by generic solutions like Claude Code that have learned Swift and can interface with external systems through MCPs. However, other challenges benefit from vertical solutions built upon existing platforms, specifically designed for app development and requiring ecosystem knowledge and expertise—which we&#39;ve developed over years of building tools for Xcode and Swift.</p>
<p>
We&#39;ll focus on areas where we can bring exceptional value within our vertical—value that organizations can perceive instantly and that wouldn&#39;t make economic sense for generic solutions to pursue. Our strong understanding of Apple&#39;s ecosystem, combined with years of solving developer pain points, positions us to deliver specialized solutions that generic tools simply can&#39;t justify building.</p>
<p>
We built Tuist to help teams and developers address existing challenges, but also to explore ideas that make development more enjoyable and accessible to everyone. We want more people building more apps for the Apple ecosystem.</p>
<hr class="thin">
<p>
<strong>Get involved:</strong> If you&#39;re intrigued by any of these ideas or would like to try the experiences we&#39;re building, we&#39;d love to hear from you. Reach out to us at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a> or join the conversation in our community. The future of Apple development is being written now, and we believe it&#39;s better when we write it together.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist is now available on the App Store ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Download the new Tuist iOS app to access your Tuist Previews on the go ]]></summary>
      <link href="https://tuist.dev/blog/2025/07/22/tuist-ios-app"/>
      <id>https://tuist.dev/blog/2025/07/22/tuist-ios-app</id>
      <updated>Tue, 22 Jul 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
We are strong believers in leveraging the platforms we build for as much as we can and dogfooding our work to have strong empathy for anyone using our platform. While in some cases, it means we need to juggle multiple pieces (be it our CLI, server or the macOS app), we strongly believe this is the best way to build software for developers.</p>
<p>
But while the majority of teams using Tuist are building an iOS app, we haven&#39;t had an opportunity to build and integrate with this platform, until now.</p>
<p>
We&#39;re really excited to announce that Tuist is now available on the App Store. We&#39;re starting with streamlining accessing and running Tuist Previews, but we have more in store for the future.</p>
<p>
<a href="https://apps.apple.com/us/app/tuist/id6748460335">  <img src="/marketing/images/blog/2025/07/22/tuist-ios-app/download-app-store.png" alt="Download on the App Store">
</a></p>
<img alt="Download on the App Store" src="/marketing/images/blog/2025/07/22/tuist-ios-app/tuist-app.png" width="300">
<p>
Delivering a high-quality iOS app is not easy. To ensure the best experience for your users, you need to test apps often, otherwise, bugs will inevitably creep in. And the best time to test a new feature is still in the PR stage. Instead of checking out a branch and compiling the changes, a time-consuming process, teams often fully re-test the new changes from a nightly build. But at that point, it&#39;s really difficult to pinpoint when a regression was introduced. </p>
<p>
<a href="https://docs.tuist.dev/en/guides/features/previews">Tuist Previews</a> aim to solve this problem by providing an extremely easy way to test your app. What started as a CLI command to share apps via links has evolved into a comprehensive ecosystem of tools that bring testing closer to where development and QA teams actually work. We&#39;ve already made installing previews on macOS as easy as clicking a button with our <a href="/blog/2024/08/28/tuist-macos-app">menu bar app</a>. Now, we&#39;re taking the same step on iOS with our Tuist app, creating a unified experience across Apple&#39;s platforms.</p>
<h2 id="tuist-app-features" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist app features<a href="#tuist-app-features" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist app features"></a></h2>
<p>
In the Tuist app, you can see the latest previews for your projects – and you can tap on any preview to see it in detail, such as to see who created the preview or which commit it&#39;s related to. In both the list of previews and the detail view, there&#39;s a &quot;Run&quot; button that allows you to run the preview directly on your device.</p>
<p>
Additionally, clicking on any preview link – or scanning a QR code – will open the preview in the Tuist app:</p>
<img alt="Download on the App Store" src="/marketing/images/blog/2025/07/22/tuist-ios-app/tuist-ios-app.gif" width="300">
<p>
To see the app in action, you can also watch the following video:</p>
<iframe title="Tuist iOS app" width="560" height="315" src="https://videos.tuist.dev/videos/embed/dYZAKZqx75PGWetFjZj2QA" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="native-developer-experiences-for-native-engineers" tabindex="-1" class="marketing__blog_post__body__content__heading">
Native developer experiences for native engineers<a href="#native-developer-experiences-for-native-engineers" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Native developer experiences for native engineers"></a></h2>
<p>
While the app is currently laser-focused on previews, the app is also a foundation block for us to build more native features for Tuist. Imagine triggering a release build or running a QA agent directly from your phone – and having a live activity that tracks the progress. These kinds of native developer experiences have been missing from the iOS ecosystem and we hope to fill in the gap.</p>
<p>
Let us know your feedback over at our <a href="https://community.tuist.dev/">community forum</a> or <a href="https://tuist.dev/slack">Slack</a>. And since the <a href="https://github.com/tuist/tuist/tree/main/app">app</a> is fully open-source and written in SwiftUI, this might be the perfect opportunity for you to get involved with open source if you&#39;d like to improve the app yourself.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Elixir Patterns We'd Love to See in Swift ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Exploring the patterns and developer experiences in Elixir that captured our hearts while building Tuist's server. From hot-reloading to server-driven UI, discover the features we'd love to see inspire Swift's evolution as it grows beyond Apple platforms. ]]></summary>
      <link href="https://tuist.dev/blog/2025/07/15/elixir"/>
      <id>https://tuist.dev/blog/2025/07/15/elixir</id>
      <updated>Tue, 15 Jul 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<strong>This blog post is written for developers who want to understand why we chose Elixir for our server, how Swift and Elixir compare, and which Elixir patterns we&#39;d love to see adopted in Swift.</strong></p>
<p>
<a href="https://en.wikipedia.org/wiki/Steve_Jobs">Steve Jobs</a> said that <a href="https://www.themarginalian.org/2011/12/21/steve-jobs-bicycle-for-the-mind-1990/">computers are bicycles for the mind</a>. I think programming languages are too. They are tools for expression, to be creative.</p>
<p>
At Tuist, we&#39;ve been huge fans of <a href="https://www.swift.org/">Swift</a>, the most common programming language of the ecosystem we build for. Yet, we always remained open to finding the right programming language or technology that would allow us to express what we wanted to express.</p>
<p>
Through Swift, we could express ourselves in terminals. We built Tuist&#39;s main CLI and filled some gaps with other open source tools like <a href="https://github.com/tuist/noora">Noora</a>. Through <a href="https://vitepress.dev/">VitePress</a>, a JavaScript-based solution, we could build a documentation website for our community with built-in search, llm.txt generation, in multiple languages. And then the time to build a server came, and with it the decision to choose the best expression tool.</p>
<p>
We needed a solution that allowed us to build and maintain a powerful and simple solution with as few resources as possible. Primarily because we were limited in budget, but also because simpler software is easier to reason about and evolve.</p>
<p>
At the time, we had come across <a href="https://elixir-lang.org/">Elixir</a> and immediately felt it was the right tool to express ourselves in a new domain: the web. We discovered patterns and approaches that we absolutely fell in love with—patterns that we believe could inspire and enhance Swift&#39;s evolution, especially as it continues to grow beyond Apple platforms.</p>
<p>
In this post, we&#39;ll walk you through what made us fall in love with Elixir, the incredible developer experience it provides, and the patterns we&#39;d love to see influence Swift&#39;s future.</p>
<h2 id="erlang-and-processes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Erlang and Processes<a href="#erlang-and-processes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Erlang and Processes"></a></h2>
<p>
We can&#39;t understand Elixir without talking about Erlang. <a href="https://www.erlang.org/">Erlang</a> is a programming language and runtime created at Ericsson in the 1980s to power their telecommunication networks. It was designed to build highly-concurrent, scalable, and fault-tolerant software. Sounds familiar? These needs are common across the modern web applications that we build today. Erlang comprises a runtime (BEAM), a programming language (Erlang), and a set of primitives to architect your apps (OTP - Open Telecom Platform). At the core of Erlang sits the idea of processes upon which almost everything builds. Joe Armstrong captured what led him to processes in his <a href="https://erlang.org/download/armstrong_thesis_2003.pdf">thesis</a>. He refers to it as <em>Concurrency Oriented Programming</em>:</p>
<p>
<em>The word concurrency refers to sets of events which happen simultaneously. The real world is concurrent, and consists of a large number of events many of which happen simultaneously. At an atomic level our bodies are made up of atoms, and molecules, in simultaneous motion. At a macroscopic level the universe is populated with galaxies of stars in simultaneous motion.</em></p>
<p>
<em>When we perform a simple action, like driving a car along a freeway, we are aware of the fact that there may be several hundreds of cars within our immediate environment, yet we are able to perform the complex task of driving a car, and avoiding all these potential hazards without even thinking about it. In the real world sequential activities are a rarity. As we walk down the street we would be very surprised to find only one thing happening, we expect to encounter many simultaneous events.</em></p>
<p>
<em>If we did not have the ability to analyze and predict the outcome of many simultaneous events we would live in great danger, and tasks like driving a car would be impossible. The fact that we can do things which require processing massive amounts of parallel information suggests that we are equipped with perceptual mechanisms which allow us to intuitively understand concurrency without consciously thinking about it.</em></p>
<p>
<em>When it comes to computer programming things suddenly become inverted. Programming a sequential chain of activities is viewed the norm, and in some sense is thought of as being easy, whereas programming collections of concurrent activities is avoided as much as possible, and is generally perceived as being difficult.</em></p>
<p>
<em>I believe that this is due to the poor support which is provided for concurrency in virtually all conventional programming languages. The vast majority of programming languages are essentially sequential; any concurrency in the language is provided by the underlying operating system, and not by the programming language.</em></p>
<p>
So the world (and agentic software) is made of concurrent processes that communicate with each other by passing messages. When I read that, I was fascinated. I had never stopped to see the world that way, but I was hooked by the idea.</p>
<p>
Processes in Erlang are lightweight and CPU/memory-isolated runtime elements that can communicate by passing messages and form more complex structures holding state, build supervised trees, define error boundaries, and work across environments (among others). This might sound too abstract at this point, but throughout the blog post I&#39;ll make it more concrete with examples of how this materializes.</p>
<h2 id="parallelism" tabindex="-1" class="marketing__blog_post__body__content__heading">
Parallelism<a href="#parallelism" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Parallelism"></a></h2>
<p>
Modern CPU architecture comprises multiple cores, which presents programming languages with the challenge of using them in the most efficient way possible. Every programming language solves this problem differently, each with its own approach and philosophy.</p>
<p>
Swift has introduced a novel approach with its structured concurrency model. Apple continues to iterate on this model to make concurrent programming safer and more intuitive. The introduction of async/await, actors, and task groups represents a thoughtful evolution in how we think about concurrent code. What&#39;s particularly exciting is seeing Swift adopt the actor model—a concept that has proven itself in distributed systems for decades.</p>
<p>
Erlang&#39;s process-based mental model resonated particularly well with us. The idea that you can write concurrent code without constantly thinking about concurrency felt magical. Processes are isolated by default, communicate through message passing, and the runtime handles the scheduling across available cores. This approach means you can focus on solving your problem rather than managing concurrency primitives.</p>
<p>
But what truly captured our imagination was how Erlang takes actors beyond just a concurrency model and makes them an architectural foundation. Tools like <a href="https://hexdocs.pm/elixir/GenServer.html">GenServer</a> (Generic Server) provide a standard way to implement stateful processes with clean APIs, while <a href="https://hexdocs.pm/elixir/Supervisor.html">Supervisors</a> create hierarchical structures that define how your system starts, stops, and recovers from failures.</p>
<p>
We&#39;d love to see Apple explore expanding actors from a concurrency primitive to a fuller architectural pattern. Imagine Swift actors that could:</p>
<ul>
  <li>
Define standard patterns for stateful services (like GenServer)  </li>
  <li>
Build supervision trees that handle failure and recovery  </li>
  <li>
Provide built-in patterns for common architectural needs  </li>
</ul>
<p>
Swift&#39;s actor model already provides excellent isolation and state management. Taking inspiration from Erlang&#39;s OTP (Open Telecom Platform), Swift could evolve to offer similar architectural patterns that make building resilient, distributed systems as natural as building a single-threaded application. The foundation is there—Swift&#39;s actors are already a powerful abstraction. The opportunity lies in building the architectural patterns on top.</p>
<h2 id="welcome-elixir" tabindex="-1" class="marketing__blog_post__body__content__heading">
Welcome Elixir<a href="#welcome-elixir" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Welcome Elixir"></a></h2>
<p>
How does Elixir connect to all of this, you might wonder? <a href="https://twitter.com/josevalim">José Valim</a>, creator of Elixir, came from the Ruby &amp; Ruby on Rails community motivated by making Ruby use all the CPU cores available. He came across Erlang and fell in love with its principles and foundation, but he realized that the language, the toolchain, and the ecosystem could benefit from modernization. He decided to build <a href="https://elixir-lang.org/">Elixir</a>, a programming language that compiles to Erlang bytecode to run in the Erlang runtime. So in other words, Erlang and Elixir are two programming languages that compile to run on the Erlang VM. As you can imagine, the language draws a lot of inspiration from Ruby, and in many ways, it feels like writing Ruby but with a more functional touch to it. If you&#39;ve used <a href="https://www.swift.org/documentation/package-manager/">SwiftPM</a> or <a href="https://doc.rust-lang.org/cargo/">Cargo (Rust)</a>, the developer experience is similar. You have a build system, <code class="inline">mix</code>, which takes care of managing your dependencies, building the project, spawning the test runner, or formatting the code, among others.</p>
<p>
So with Elixir, you get the power and the simplicity of a battle-tested runtime (Erlang&#39;s) with a modern toolchain, language, and ecosystem that makes building for Erlang a true joy.</p>
<h2 id="tuist-meets-elixir" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist Meets Elixir<a href="#tuist-meets-elixir" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist Meets Elixir"></a></h2>
<p>
Having talked about Elixir, Erlang, and processes, it&#39;s time to talk about the patterns and experiences we discovered that we&#39;d love to see inspire Swift&#39;s evolution. Note that some of the value that I&#39;ll touch on is a shared responsibility between Elixir as a programming language and Erlang as a runtime and framework, but I&#39;ll refer to it as just Elixir value. Let&#39;s dive into some day-to-day real impacts on how we are building Tuist.</p>
<h3 id="a-build-system-that-doesn't-get-in-your-way" tabindex="-1" class="marketing__blog_post__body__content__heading">
A Build System That Doesn&#39;t Get in Your Way<a href="#a-build-system-that-doesn't-get-in-your-way" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A Build System That Doesn't Get in Your Way"></a></h3>
<p>
The Elixir build system is absolutely amazing and represents a pinnacle of developer experience. Like any other build system, it&#39;ll take some time initially to build your project (i.e., clean build), but once it&#39;s built, it magically hot-reloads your changes, making the feedback loops incredibly short. Is there a bug in one of the web app routes? I change one line of code, and the change is picked up automatically. This developer experience has spoiled us—the ability to see changes instantly keeps the creative momentum going.</p>
<p>
Additionally, because Elixir is functional, the reconciliation of the changes at runtime leads to expected results. The build system feels invisible in the best possible way—it&#39;s there when you need it but never gets in your way.</p>
<p>
Swift has taken the first steps to unify the build system across SwiftPM and Xcode, and we&#39;re optimistic that it&#39;ll reach a similar level of developer experience that spans across layers. The potential for Swift to adopt hot-reloading capabilities, especially for server development, would be transformative. Imagine the productivity gains if Swift developers could experience the same instant feedback loops we enjoy with Elixir.</p>
<h3 id="read-eval-print-loop" tabindex="-1" class="marketing__blog_post__body__content__heading">
Read-Eval-Print Loop<a href="#read-eval-print-loop" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Read-Eval-Print Loop"></a></h3>
<p>
Being able to open a console with access to your codebase symbols and the history of executed instructions can make a huge productivity difference in development. For example, locally we can just do the following to debug a particular organization:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
elixir    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="elixir">
Tuist.Accounts.get_organization_by_handle(&quot;tuist&quot;) 
  |&gt; Tuist.Accounts.get_organization_members()    </shiki-highlight>
  </div>
</div>
<p>
One could say that you can come up with a similar query yourself with the help of an LLM, but if we are talking about a function that encapsulates more business logic, then things get trickier. You are forced to either write an entry point to that piece of logic when all you want is to iterate on a new idea that you came up with. The console is also able to hot-reload changes automatically for you, so you can keep typing, always assuming you&#39;ll be using the latest version of your code.</p>
<p>
This tool can also be used in production, but we use it sparingly only in very exceptional cases and with read-only operations.</p>
<h3 id="server-driven-interactive-ui" tabindex="-1" class="marketing__blog_post__body__content__heading">
Server-Driven Interactive UI<a href="#server-driven-interactive-ui" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Server-Driven Interactive UI"></a></h3>
<p>
I talked a lot about processes earlier, and if there&#39;s a good example of how cool they are, we need to talk about <a href="https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html">Phoenix LiveView</a>. <a href="https://www.phoenixframework.org/">Phoenix</a> is the Ruby on Rails of Elixir. It&#39;s the web framework that most Elixir projects use to build web apps. When it comes to doing UI, Phoenix proposes a quite unique model, LiveView, which allows us to build dynamic UIs without having to worry about managing API-provided client-side state or dealing with the cost of a JavaScript runtime setup (and its ecosystem).</p>
<p>
Phoenix LiveView&#39;s model is absolutely brilliant. When you open a page, a process is created and bound to your connection, with a state that&#39;s then mapped to HTML that&#39;s presented in your browser. Since the state is on the server, you don&#39;t need to deal with syncing state between client and server. Any action that requires UI change is sent to the server, the new state is calculated, mapped to a new representation, and Phoenix LiveView takes care of sending the diff to the client. In our particular context, having a single source of truth for UI state was crucial, and LiveView delivered this beautifully.</p>
<p>
The Swift community is pushing Swift to new environments like the browser using WebAssembly, and we can&#39;t wait to see the answer the community comes up with to build dynamic UIs. Perhaps we&#39;ll see Swift-native solutions that bring similar server-driven UI capabilities, combining Swift&#39;s type safety with real-time reactivity.</p>
<p>
For example, our <a href="https://github.com/tuist/tuist/blob/main/server/lib/tuist_web/live/preview_live.ex">preview</a> page uses LiveView. You&#39;ll notice that we fetch the state, assign it to the socket connection, and then <a href="https://github.com/tuist/tuist/blob/main/server/lib/tuist_web/live/preview_live.html.heex">use it in the template</a>. Because templates are compiled, the runtime has all the information it needs to optimize the diff that&#39;s sent to the client. The mental model is refreshingly simple yet powerful.</p>
<h3 id="real-time-ui" tabindex="-1" class="marketing__blog_post__body__content__heading">
Real-Time UI<a href="#real-time-ui" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Real-Time UI"></a></h3>
<p>
People are expecting more and more UIs to update in real-time as new data comes in. In the context of Tuist, we&#39;ll have a lot of things happening, from a new build that&#39;s pushing logs to our server, to a preview that&#39;s being built to be shared with other users.</p>
<p>
Phoenix provides <a href="https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html">PubSub</a>, whose default adapter leverages Erlang capabilities to discover and distribute messages across nodes. Let&#39;s say you are seeing the builds page, and a new build comes in. Erlang could receive a message saying that a new build has been created, and we can have LiveViews subscribed to those events updating their internal state accordingly and sending the diffs to the client.</p>
<p>
Swift&#39;s distributed actors model draws a lot of inspiration from similar actor-based systems, and we believe it could be a great foundation to build real-time applications in Swift too. The conceptual similarities between Erlang&#39;s processes and Swift&#39;s actors suggest that Swift could evolve to provide similar built-in real-time capabilities.</p>
<p>
This capability of Erlang is so powerful that companies like <a href="https://discord.com/blog/how-discord-scaled-elixir-to-5-000-000-concurrent-users">Discord</a> and <a href="https://www.erlang-solutions.com/blog/20-years-of-open-source-erlang-openerlang-interview-with-anton-lavrik-from-whatsapp/">WhatsApp</a> have built their infrastructure on it. At Tuist, we&#39;re investing more in making our features real-time, and this foundation also enables collaborative features where multiple people can interact with the same state—think of experiences like Figma.</p>
<h3 id="ease-of-scaling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Ease of Scaling<a href="#ease-of-scaling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Ease of Scaling"></a></h3>
<p>
We are a small team, so it&#39;s important that as the need for scaling comes, we don&#39;t need to invest many resources into it. Both Swift and Elixir excel in this area—they&#39;re languages designed to scale elegantly.</p>
<p>
With Elixir, we can build powerful solutions like real-time capabilities and collaborative experiences without complex setup. Most of our surfaces are a database schema, a small piece of business logic in between, and a LiveView. The simplicity is refreshing.</p>
<p>
Testing is another area where scalability matters. Every test in Elixir is a different process, scheduled to run in parallel. If you want to run your test suite faster, you can throw more CPU cores at the problem. But what&#39;s particularly elegant is how Elixir&#39;s functional nature encourages writing tests that are naturally isolated. Since most of the time you&#39;re testing pure functions that take inputs and return outputs, there&#39;s little opportunity for shared state to cause flakiness. When you do need stateful processes in tests, you can spawn them in isolation.</p>
<p>
This got us thinking about how powerful it would be if foundation APIs were designed with this principle in mind—actively discouraging global state that might leak across concurrent tests. Swift already has tools like <a href="https://developer.apple.com/documentation/swift/tasklocal">TaskLocal</a> that could play a role in scoping state to tests, but we don&#39;t see this being actively promoted as a pattern the community should adopt for test isolation. Imagine if Swift&#39;s testing frameworks and foundation libraries were architected to make the isolated approach the path of least resistance, with clear patterns and best practices for state isolation. The functional model guides this good behavior in Elixir, but similar outcomes could be achieved through thoughtful API design and community conventions that make shared mutable state difficult to accidentally introduce.</p>
<p>
In Elixir, you can even define mocks scoped to each test&#39;s process tree, ensuring complete isolation. This pattern—where the foundation actively guides you toward scalable, flake-free testing—is something we&#39;d love to see more broadly adopted.</p>
<p>
In production, Elixir&#39;s concurrent nature allows scaling vertically by simply adding more memory and CPU. Erlang&#39;s scheduler ensures those resources are used optimally. We run our app on <a href="https://fly.io/">Fly.io</a>, which makes it trivial to add machines in different regions to reduce latency for global users.</p>
<p>
The beauty of both Swift and Elixir is that they make scaling feel natural rather than an afterthought. Swift&#39;s performance characteristics and Elixir&#39;s concurrency model are different approaches to the same goal: building systems that grow with your needs.</p>
<h3 id="the-ecosystem" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Ecosystem<a href="#the-ecosystem" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Ecosystem"></a></h3>
<p>
When comparing ecosystems, it&#39;s important to acknowledge that it&#39;s not quite a fair comparison—Erlang has been battle-tested in production since the 1980s, giving it decades to mature and develop specialized solutions. The Elixir ecosystem benefits from this foundation, with focused, well-established libraries for most server-side needs.</p>
<p>
Swift&#39;s server ecosystem, by contrast, is young and vibrant. What excites us is the momentum we&#39;re seeing—more companies are investing in Swift on the server, bringing fresh perspectives and innovative solutions. The community&#39;s energy around pushing Swift beyond Apple platforms is palpable, and we&#39;re optimistic that this ecosystem will become increasingly diverse and robust.</p>
<p>
For our current needs, we found everything required in the Elixir ecosystem. When we added <a href="https://clickhouse.com/">ClickHouse</a> to our infrastructure, <a href="https://plausible.io/">Plausible</a> had already built an adapter. When we needed OpenID Connect, <a href="https://github.com/malach-it/boruta_auth">Boruta</a> was ready to go. This maturity meant we could focus on building rather than filling gaps.</p>
<p>
But we&#39;re watching Swift&#39;s server ecosystem with great interest. As more teams adopt Swift on the server and share their solutions, we expect to see similar depth emerge. The quality of what&#39;s already available—from web frameworks to database drivers—shows that Swift&#39;s server future is bright. In a few years, we believe Swift developers will enjoy the same rich ecosystem that makes Elixir development so productive today.</p>
<p>
The excellent documentation quality across the Elixir ecosystem has been crucial for our productivity, especially in an age of AI-assisted development. This is something the Swift community has always excelled at, and we&#39;re confident this tradition will continue as the server ecosystem grows.</p>
<h2 id="trade-offs-and-what-we-miss" tabindex="-1" class="marketing__blog_post__body__content__heading">
Trade-offs and What We Miss<a href="#trade-offs-and-what-we-miss" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Trade-offs and What We Miss"></a></h2>
<p>
Choosing Elixir meant accepting certain trade-offs, and there are definitely things we miss from the Swift world:</p>
<p>
<strong>Shared code between CLI and server</strong>: One of the most significant trade-offs is not being able to share models and business logic between our Swift CLI and Elixir server. In an all-Swift setup, we could have a single source of truth for our domain models, reducing duplication and potential inconsistencies.</p>
<p>
<strong>Memory control for resource-intensive tasks</strong>: While Elixir excels at concurrent I/O-bound operations, Swift&#39;s more direct memory control would be advantageous for potential future resource-intensive tasks. If we ever need to do heavy computational work, Swift&#39;s performance characteristics would be ideal.</p>
<p>
<strong>Compile-time guarantees</strong>: Swift&#39;s compiler catches entire categories of errors through static type checking. While Elixir&#39;s dynamic nature enables certain patterns like hot-reloading, we do miss the confidence that comes from Swift&#39;s type system, especially during large refactorings.</p>
<p>
These are genuine trade-offs that we considered carefully. For our current needs—building a real-time, collaborative platform—Elixir&#39;s benefits outweighed these costs, but we remain excited about Swift&#39;s evolution in the server space.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing Words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing Words"></a></h2>
<p>
In hindsight, Elixir was the right bicycle for the job of building the Tuist platform today. Our 4-person team feels incredibly productive, and the patterns we&#39;ve discovered—from hot-reloading to server-driven UI to built-in real-time capabilities—have shaped how we think about building software.</p>
<p>
But we&#39;re equally excited about Swift&#39;s future. As Swift continues to evolve beyond Apple platforms, we hope to see it adopt some of the patterns that make Elixir such a joy to work with. Imagine Swift with hot-reloading, built-in real-time primitives, or Phoenix LiveView-style server-driven UI capabilities. The combination of Swift&#39;s type safety and performance with Elixir&#39;s developer experience would be incredible.</p>
<p>
We&#39;re keeping a close eye on Swift&#39;s evolution, and who knows? As the ecosystem matures and new capabilities emerge, we might revisit this decision in the future. For now, we&#39;re grateful for what both languages bring to the table and excited to see how they&#39;ll continue to inspire each other.</p>
<p>
Thank you to both José Valim and the Elixir community, and to Chris Lattner and the Swift community, for gifting us with such wonderful tools for expression.</p>
<p>
<strong>Grammar corrections provided by Claude Opus 4.</strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Server is Now Source Available ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We're thrilled to announce that the Tuist Server is now source available. After years of building open source tools for the mobile development community, we're taking a significant step toward greater transparency while ensuring sustainable development. ]]></summary>
      <link href="https://tuist.dev/blog/2025/07/08/server-fcl"/>
      <id>https://tuist.dev/blog/2025/07/08/server-fcl</id>
      <updated>Tue, 08 Jul 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
At Tuist, we are huge advocates of openness. We started Tuist as an open source Xcode project generator CLI and eventually built a business around the awesome foundation we’ve been developing for more than 7 years. As part of that effort, we’ve gifted the community open source solutions like <a href="https://github.com/tuist/noora">Noora</a>, which was featured on <a href="https://www.swift.org/">Swift’s new website</a>, <a href="https://github.com/tuist/xcodeproj">XcodeProj</a>, which many CLI tools depend on, and <a href="https://github.com/tuist/xcodegraph">XcodeGraph</a>, which we extracted from our project generation CLI and made available to everyone.</p>
<p>
Unfortunately, we couldn’t open everything in the early days of the company because we hadn’t figured out where we could capture value. This left us with an itch. We knew this would be temporary and that we’d figure out a path back to openness, so I’m thrilled to announce that the Tuist Server is now <a href="https://github.com/tuist/tuist/tree/main/server">source available</a>.</p>
<h2 id="why-we’re-opening-the-source-code" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why we’re opening the source code<a href="#why-we’re-opening-the-source-code" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why we’re opening the source code"></a></h2>
<p>
We love working with the community. Openness eliminates barriers and makes you more accountable, leading to a much better product. When you’re building in the open, every decision gets scrutinized, every bug gets reported, and every feature request comes with real use cases attached. If we want to build the best virtual platform team for mobile developers, this is the way.</p>
<p>
We see building an open company as a long-term game. While closed source code combined with capital can give you an initial advantage and help you move fast in the short term, the momentum a project can build over time with its community is absolutely unbeatable. There’s no better example than Microsoft’s strategic investments in <a href="https://code.visualstudio.com/">VSCode</a> and <a href="https://www.typescriptlang.org/">TypeScript</a> that have fundamentally shaped how developers work today. Our role models are companies like <a href="https://gitlab.com">GitLab</a>, <a href="https://grafana.com">Grafana</a>, and <a href="https://supabase.com">Supabase</a>, who’ve proven that you can build sustainable businesses while staying true to open principles. We aim to take a similar role in the mobile development space.</p>
<p>
The mobile development ecosystem desperately needs this kind of openness. For too long, we’ve been stuck with proprietary tooling that doesn’t evolve fast enough or address the real pain points developers face daily. By opening our source, we’re creating transparency around our technical decisions and making ourselves more accountable to the community we serve.</p>
<h2 id="capturing-value-to-fund-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Capturing value to fund development<a href="#capturing-value-to-fund-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Capturing value to fund development"></a></h2>
<p>
But here’s the reality: you need to fund development. In other words, you need to capture some of the value you produce, or the project will eventually stagnate like so many promising open source initiatives we’ve seen over the years. I really enjoyed this talk from <a href="https://www.youtube.com/watch?v=gyog9RJ2jHs">Penpot</a>, where they emphasized that open source captures less value than proprietary versions, but it’s also true that the ability to produce value in open source is much higher because of the transparency and community trust it builds.</p>
<p>
This is where many open source projects fail—they focus so much on being “free” that they forget sustainability. We’ve seen countless projects start with massive enthusiasm, only to fade away because the maintainers burned out or couldn’t afford to keep working on them. We refuse to let that happen to Tuist. Our commitment is to continue investing heavily in the development of Tuist with our full-time team, ensuring consistent progress and innovation.</p>
<p>
So how do you capture value responsibly? Every company decides on the model that aligns best with their mission and capabilities. Some organizations prefer focusing on services, for example by offering premium support, educational material, or hosting as a service. Others prefer capturing value through product innovation, so they embrace a licensing model that allows them to draw clear lines around what’s free and what’s paid. Many successful companies do a thoughtful mix of both approaches.</p>
<p>
At Tuist, <strong>we realized early on that what energizes us most is building product rather than providing services.</strong> We’re engineers at heart—we love solving complex technical problems and creating tools that make developers’ lives better. We used this self-awareness as our guiding principle to find our model.</p>
<h2 id="finding-our-model" tabindex="-1" class="marketing__blog_post__body__content__heading">
Finding our model<a href="#finding-our-model" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Finding our model"></a></h2>
<p>
Early on, we naively suffered from the <a href="https://en.wikipedia.org/wiki/Free-rider_problem">free-rider problem</a>. At the time, we thought developers would naturally pay for hosting the server or use our hosted instance, but the ease of self-hosting for both us and other companies—which could potentially put Tuist at competitive risk—turned out not to be a sustainable approach. So we bought ourselves some time and space to figure out the right model by developing some pieces as closed source. We knew this would be temporary until we could better understand our customers and their willingness to pay for value.</p>
<p>
Thanks to that strategic pause, we’re now steadily capturing part of the market and understanding our customers much better, which allows us to start reverting the closing of some components. At the same time, hosting and maintaining an instance of Tuist is becoming increasingly complex—not because we made it intentionally difficult, but because it’s the natural result of solving more sophisticated problems that our enterprise customers face. Still, this complexity alone isn’t enough motivation for many organizations to pay us for hosting. We needed to find a step in between full open source and completely closed.</p>
<p>
The challenge was finding a model that would let us be as open as possible while still ensuring we could sustain and grow the team working on Tuist. We didn’t want to fall into the trap of either giving everything away for free (and risking project stagnation) or being so restrictive that we lost the community benefits of openness.</p>
<h2 id="fair-core-license" tabindex="-1" class="marketing__blog_post__body__content__heading">
Fair Core License<a href="#fair-core-license" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Fair Core License"></a></h2>
<p>
We then discovered <a href="https://fair.io/licenses/">fair source licenses</a>, which aren’t traditional open source licenses but provide a compelling middle ground. One of the largest promoters of this approach is <a href="https://sentry.io">Sentry</a>, and their success gave us confidence in the model. Fair licenses buy you crucial time by preventing the free ride issue while committing to defer open source by 2 years since the code has been contributed. This sounded like exactly what we needed—protection from free riding that allows us to focus on building the best product we can imagine, while creating software that will eventually be available under an OSI-approved license.</p>
<p>
The beauty of this approach is that it aligns incentives properly. Companies that want to use Tuist Server commercially either pay us (supporting continued development) or wait two years and use it for free (by which time we’ve moved on to newer innovations). It’s a fair trade that respects both our need to capture value and the community’s expectation of eventual openness.</p>
<p>
So today, the server has joined the <a href="https://github.com/tuist/tuist">tuist/tuist</a> monorepo under the Fair Core License. Of all the fair licenses available, FCL also gives us the flexibility to place some features behind a paid license, which is crucial in our current phase where we don’t have many features that are directly monetizable yet. While the line we’ve drawn might seem strict today, our plan is to progressively lift restrictions as we develop more enterprise-focused features, until we can have distinct community and enterprise versions—or who knows, maybe infrastructure hosting is where we’ll capture most of our value, at which point we might embrace Sentry’s simpler license and offer all features as long as you don’t try to compete directly with us.</p>
<h2 id="it’s-a-fluid-model" tabindex="-1" class="marketing__blog_post__body__content__heading">
It’s a fluid model<a href="#it’s-a-fluid-model" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to It’s a fluid model"></a></h2>
<p>
We see FCL as an intermediate step in our journey, not a final destination. As the project matures and the needs of our users continue to evolve, we’ll regularly reassess opportunities to revisit and relax the license terms. For example, if we develop more sophisticated enterprise features—think advanced analytics, compliance tools, or enterprise integrations—we could adjust where we draw the line between free and paid. If we discover we can capture more value from the infrastructure and hosting side, we could potentially lift the licensing restrictions entirely and focus on our cloud offering, which we’re uniquely positioned to excel at since we developed the underlying software ourselves.</p>
<p>
And who knows—if the mobile development market grows large enough and our business model proves sustainable, we could even eliminate the deferred open sourcing requirement entirely. But this is very far into the future. The model could eventually look similar to GitLab’s successful open core approach, where there’s a clear distinction between community and enterprise features.</p>
<p>
The key is staying flexible and responsive to what our community and customers actually need, rather than getting locked into a rigid ideological position about licensing.</p>
<h2 id="what-changes-for-me?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What changes for me?<a href="#what-changes-for-me?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What changes for me?"></a></h2>
<p>
I imagine many of you are wondering what this actually means for your day-to-day work with Tuist. The short answer is: probably not much. Let me break this down.</p>
<p>
If you&#39;re a developer who loves contributing to open source projects, <strong>the Tuist CLI and all our core tooling remains exactly as it was</strong>—MIT licensed and completely open for contributions. You can continue submitting PRs, reporting issues, and helping shape the future of mobile development tooling without any additional friction. The server components now require a simple contributor agreement, but we&#39;ve designed this process to be as straightforward as possible because we genuinely want your contributions.</p>
<p>
For organizations evaluating Tuist, <strong>you can run the server locally for development and testing purposes</strong>. The source code is publicly available, you can inspect every line, and modify it for your needs. However, if you want to deploy it in your production infrastructure, you&#39;ll need to obtain a license from us to legally use it in that capacity. This licensing approach ensures we can continue investing in the platform while still maintaining transparency around our technical decisions.</p>
<p>
If managing that infrastructure sounds overwhelming (and for many teams, it absolutely should), <strong>our hosted service remains the easiest path forward</strong>. We handle all the complexity while you focus on building great apps. This is where we capture value to fund continued development, and it&#39;s a model that&#39;s worked well for companies like GitHub, GitLab, and countless others in the developer tools space.</p>
<h2 id="closing-thoughts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing thoughts<a href="#closing-thoughts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing thoughts"></a></h2>
<p>
When you make a tool part of your development stack, you&#39;re placing tremendous trust in us to support your journey, and we&#39;ve always felt deeply responsible for honoring that trust with an unwavering commitment to always be there for you. We focused on building a source of revenue so our passionate team could focus on Tuist full time without worrying about sustainability. We then announced our <a href="/longevity">longevity commitment</a>, which legally ensures that regardless of what happens to Tuist as a company, your projects and workflows won&#39;t get disrupted. We embraced a transparent pricing model and product design that actively fought against predatory enterprise practices like &quot;contact sales&quot; gatekeeping or feature-limited demo products that were unfortunately becoming the norm in our space.</p>
<p>
We’ll continue open sourcing and gifting valuable projects to the community, like XcodeProj, Noora, Rosalind, and XcodeGraph—and who knows, maybe even the server itself will be fully open source in the future as our business model continues to evolve.</p>
<p>
Tuist aims to be your virtual platform team for building incredible apps, and we believe this ambitious goal is only possible if we become more open and collaborative, not less. The future of mobile development is too important to build behind closed doors, and we’re committed to leading by example with the resources and dedication this vision deserves.​​​​​​​​​​​​​​​​</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ The Future of App Development: Tuist Previews in an AI-Powered World ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ As AI transforms how we write code, we're reimagining how Tuist Previews can bridge the gap between automated development and human validation. Here's our vision for the future of mobile app development. ]]></summary>
      <link href="https://tuist.dev/blog/2025/06/19/previews"/>
      <id>https://tuist.dev/blog/2025/06/19/previews</id>
      <updated>Thu, 19 Jun 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
There&#39;s no question at this point that AI will have an impact on the way we write code.
We touched on this in our <a href="/blog/2025/05/13/vibe-xcoding">Vibe Xcoding your Apps</a>, and most recently we&#39;ve seen Apple taking steps toward reconciling recent innovations, like agentic coding workflows, into Xcode.
There&#39;s no turning back. However, development is just part of the equation.
If things continue this way, there&#39;s a high chance that an agent can take your task,
run it in a macOS environment,
and come back with a PR.
But what happens from that point on?
This is something we&#39;re exploring at Tuist,
and we believe Tuist Previews can play a pivotal role in this new landscape.</p>
<h2 id="between-pr-opening-and-merge" tabindex="-1" class="marketing__blog_post__body__content__heading">
Between PR Opening and Merge<a href="#between-pr-opening-and-merge" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Between PR Opening and Merge"></a></h2>
<p>
If you think of traditional workflows in Swift app development, 
which closely mirror workflows in other technologies,
once a PR is opened,
two main things happen. First,
your peers review the code to ensure it&#39;s correct.
Second, you trigger one or multiple CI jobs that run automated checks against your changes.
If both give the green light, you merge the PR.</p>
<p>
Whether through Tuist&#39;s optimizations like binary caching or selective testing,
or in the near future with swift-build optimizations,
combined with the decreasing cost of Mac infrastructure,
the financial and time cost of running automated checks will become minimal.
In other words, you&#39;ll get CI results in minutes or even seconds.
This sounds idealistic,
but in the world of agents, where fast feedback is crucial,
we believe this will become reality.</p>
<p>
What does this mean? If you automate code review using AI tools like <a href="https://www.anthropic.com/claude-code">Claude Code</a> or <a href="https://github.com/features/copilot">GitHub Copilot</a>,
which analyze code patterns and best practices,
what remains is ensuring that the changes do what they&#39;re supposed to do.
This requires compiling, launching, and using the app—
and this is where <a href="https://docs.tuist.dev/en/guides/features/previews">Tuist Previews</a> become essential.</p>
<h2 id="previews:-a-tool-to-manually-test-your-changes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Previews: A Tool to Manually Test Your Changes<a href="#previews:-a-tool-to-manually-test-your-changes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Previews: A Tool to Manually Test Your Changes"></a></h2>
<p>
When we introduced previews,
we drew inspiration from platforms like <a href="https://vercel.com/">Vercel</a>, <a href="https://www.cloudflare.com/">Cloudflare</a>, and <a href="https://www.netlify.com/">Netlify</a>,
where you get an ephemeral environment accessible via URL to see your changes live.
We also took cues from <a href="https://shopify.engineering/shopify-tophat-mobile-developer-testing">Shopify&#39;s &quot;tophat&quot; culture</a>,
where developers are required to test changes as part of reviewing PRs.
We loved this concept and brought it to the mobile app world through Tuist.</p>
<p>
For previews to succeed, they need to be available no slower than the longest wait between CI checks or review approvals. Let&#39;s say both happen in under 5 minutes. If your preview takes 10 minutes to build, authors will likely merge without peers manually testing the changes.
That&#39;s why we&#39;re heavily invested in cutting build times so that preview generation is comparable to CI check times, while also reducing the costs of creating previews (since CI typically charges per build minute).</p>
<p>
The second crucial piece is ensuring previews are seamless to run. <strong>We designed them to be URL-centric.</strong> When someone shares a URL with you, you should be able to install the preview just by tapping the URL, or pasting it in the terminal if you have the CLI installed. And if the app supports physical devices and your device ID is in the signing certificate, you can install it on your device too.</p>
<p>
Many people compare previews with <strong>nightly builds</strong> because, as I pointed out in <a href="/blog/2025/05/20/business-around-tuist">Building a Business Around Tuist</a>, people iterate on their mental models gradually. Both nightly builds and previews are tools to build and share apps. The difference is that while nightly builds are distant in time and space from code changes—making it difficult to correlate feedback with changes—previews are immediate. They happen right at the PR level, where feedback can be provided in context and easily addressed. Compare this to getting a Slack message days later saying, &quot;Hey, I found something in build 233.&quot; Finding the PR that introduced the issue becomes increasingly difficult as merge throughput increases.</p>
<p>
If you haven&#39;t tried previews yet, it&#39;s remarkably simple. Build your project with <code class="inline">xcodebuild</code>, Fastlane, or your tool of choice, then run one command to share the app:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist share App    </shiki-highlight>
  </div>
</div>
<p>
The metadata necessary to correlate the preview with the Git forge is automatically collected. In other words, Tuist knows which PR the preview belongs to.</p>
<h2 id="time-for-feedback" tabindex="-1" class="marketing__blog_post__body__content__heading">
Time for Feedback<a href="#time-for-feedback" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Time for Feedback"></a></h2>
<p>
Getting previews into people&#39;s hands is just half the equation. We&#39;re actively working to eliminate friction through features like on-the-fly signing and bringing the experience to the web so you don&#39;t need simulators or even Apple devices. But there&#39;s more we can—and will—do. The natural next step after testing an app is reporting feedback, and this closes the development loop.</p>
<p>
This is where things get truly exciting. Imagine you&#39;re using a preview and discover an issue. Wouldn&#39;t it be powerful if the preview provided built-in tools to report that feedback? What if that feedback automatically included contextual information to help developers understand the issue? For example: redacted traces of server requests, user navigation paths through the app, logs, or even a recording of the last few minutes leading to the issue.</p>
<p>
These are just examples, but you get the idea. We&#39;re exploring the development of a <strong>Tuist Development SDK</strong> that integrates into your app&#39;s development builds, closing the loop with a feedback tool that seamlessly integrates with previews and the AI-powered coding world that&#39;s taking shape.</p>
<h2 id="what-if-you-could-automate-the-feedback-process-too?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What If You Could Automate the Feedback Process Too?<a href="#what-if-you-could-automate-the-feedback-process-too?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What If You Could Automate the Feedback Process Too?"></a></h2>
<p>
Here&#39;s where we get truly forward-thinking. Having built infrastructure to distribute previews, feedback building blocks, and the Tuist SDK, we have all the ingredients for something transformative:</p>
<ul>
  <li>
Push your changes  </li>
  <li>
Get CI and AI feedback about your code  </li>
  <li>
Get AI feedback about your app&#39;s runtime behavior  </li>
</ul>
<p>
Wouldn&#39;t that be revolutionary? We know the web is already moving in this direction, and we&#39;re eager to bring the same experience to app developers. We&#39;re doubling down on previews because we believe they can unlock a world of possibilities in this new era that&#39;s unfolding before us.</p>
<p>
The future of app development is being written right now, and we&#39;re thrilled to be part of shaping it. With curiosity as our compass and innovation as our engine, we&#39;re building the tools that will make tomorrow&#39;s development workflows feel like magic compared to today&#39;s.</p>
<p>
<strong>You can start using <a href="https://docs.tuist.dev/en/guides/features/previews">previews</a> today with Xcode projects or generated Tuist projects.</strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ The evolution of Mobile CI: Navigating the shift to Infrastructure-as-a-Service ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The mobile CI landscape is undergoing a fundamental transformation. As GitHub Actions and infrastructure providers reshape the market, we explore what this means for developers, CI providers, and the future of mobile development workflows. ]]></summary>
      <link href="https://tuist.dev/blog/2025/06/18/mobile-ci"/>
      <id>https://tuist.dev/blog/2025/06/18/mobile-ci</id>
      <updated>Wed, 18 Jun 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
At Tuist, we have the privilege of engaging with numerous organizations, understanding their challenges, and identifying their needs. One recurring theme that emerges from these conversations is continuous integration—a critical component that companies rely on not only to validate changes before merging to <code class="inline">main</code>, but also to automate release builds and App Store deployments.</p>
<p>
I&#39;ll be candid: we&#39;ve seriously considered entering the CI space ourselves to provide Tuist users with a premium, reliable solution. However, the deeper we analyzed this domain, the clearer it became that the industry is experiencing a fundamental transformation. We&#39;re witnessing the emergence of a new paradigm—one where Tuist is strategically positioned to operate at a higher abstraction layer above this evolving landscape.</p>
<h2 id="understanding-the-ci-stack" tabindex="-1" class="marketing__blog_post__body__content__heading">
Understanding the CI Stack<a href="#understanding-the-ci-stack" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Understanding the CI Stack"></a></h2>
<p>
From a user&#39;s perspective, CI appears straightforward: a service integrated with your repository that executes workflows triggered by specific actions (typically repository events like code pushes) and delivers results through logs, artifacts, and status updates. However, if we deconstruct CI into its fundamental layers, we discover three distinct components, starting from the foundation:</p>
<ul>
  <li>
    <p>
<strong>Infrastructure Layer:</strong> The bedrock requiring physical hardware and virtualization technology to run tasks in isolation. Apple&#39;s ecosystem adds unique complexity here—most tasks require Apple hardware running macOS, creating scarcity since few cloud providers offer managed Apple infrastructure.    </p>
  </li>
  <li>
    <p>
<strong>Orchestration Layer:</strong> The middleware connecting infrastructure to Git platforms like GitHub, triggering workflows based on repository events. This layer manages pipeline execution, defining the sequence and logic of tasks within each workflow.    </p>
  </li>
  <li>
    <p>
<strong>User Interface Layer:</strong> The customer-facing experience for workflow management, providing real-time execution feedback, manual triggers, and analytical insights (such as average execution times and success rates).    </p>
  </li>
</ul>
<p>
While you might not have previously considered these architectural details, this layered approach fundamentally defines how CI systems operate.</p>
<h2 id="the-mobile-devops-movement" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Mobile DevOps Movement<a href="#the-mobile-devops-movement" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Mobile DevOps Movement"></a></h2>
<p>
Several years ago, I encountered the term &quot;Mobile DevOps&quot; and found myself puzzled. My initial reaction was: &quot;Isn&#39;t Mobile DevOps essentially just Fastlane?&quot; I questioned why this concept was suddenly gaining traction and what was driving its emergence. Initially, the movement seemed unclear, but as I gained deeper industry insights, I recognized this as a strategic evolution aimed at expanding the addressable market. In business terms, companies were seeking to grow beyond traditional CI boundaries to capture larger market opportunities.</p>
<p>
DevOps makes intuitive sense in backend engineering, where teams manage production infrastructure and orchestrate complex deployments. This need spawned an entire ecosystem: foundations, open-source tools like Kubernetes, and specialized conferences. However, mobile development operates differently. Developers spend most of their time in Xcode, while CI workflows typically focus on building, testing, releasing, and linting code. For years, Fastlane successfully abstracted these needs and cultivated a thriving ecosystem around them.</p>
<p>
Yet the appetite for capturing this value persisted. Companies invested heavily in proprietary solutions designed to create ecosystem lock-in and cross-sell additional products. We&#39;ve seen everything from proprietary pipeline formats to visual pipeline editors, to custom step ecosystems that—lacking community contribution incentives—quickly became outdated. Today&#39;s landscape includes release automation, test analytics, caching solutions, and more—all under the Mobile DevOps umbrella. However, for many practitioners, these remain fundamentally CI companies, which creates both opportunities and challenges due to entrenched mental models.</p>
<p>
It&#39;s worth noting that many providers outsource infrastructure and virtualization to third parties, avoiding hardware management complexities. While this simplifies operations, it significantly impacts margins, making orchestration and UI the primary value-capture layers for most providers.</p>
<h2 id="the-runs-on-revolution" tabindex="-1" class="marketing__blog_post__body__content__heading">
The runs-on Revolution<a href="#the-runs-on-revolution" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The runs-on Revolution"></a></h2>
<p>
GitHub fundamentally disrupted the market years ago, with other platforms like GitLab and Forgejo following suit. Their decision wasn&#39;t merely to become CI providers—they opened up the architectural layers, enabling users to bring their own infrastructure or leverage specialized third-party providers.</p>
<p>
This shift has profound implications that deserve more discussion. GitHub Actions (and equivalents on other platforms) offers tight UI integration that external CI providers simply cannot match. Third-party providers are constrained by available APIs, primarily limited to updating commit statuses and adding code annotations. Meanwhile, GitHub can ship features like declarative permissions, dynamically generating workflow-scoped tokens with precise permission boundaries.</p>
<p>
The GitHub Actions ecosystem represents another strategic advantage. Initially, I assumed it was proprietary, but using Forgejo via Codeberg revealed that their CI solution supports GitHub Actions composition. Fundamentally, these are Node.js/JavaScript functions with configuration files declaring action behavior. GitHub&#39;s unique position allows them to incentivize developer contributions through a simple mental model: build an action, host it in a repository, and enhance your developer profile. This ecosystem effect is difficult to replicate. I&#39;m curious to see how <a href="https://dagger.io/">Dagger</a>&#39;s attempt to decouple actions from CI providers evolves, though their Docker-centric approach may face challenges with Apple&#39;s macOS and hardware requirements.</p>
<p>
This new model birthed a different category of companies—those focused exclusively on providing the fastest, most reliable infrastructure for CI needs. At Tuist, we recently adopted <a href="https://namespace.so/">Namespace</a> for our CI requirements and will soon leverage it for product features requiring ephemeral macOS environments. The setup process is remarkably simple: install a GitHub app and update the <code class="inline">runs-on</code> attribute in your workflow files.</p>
<p>
The <code class="inline">runs-on</code> attribute represents one of the most elegant <a href="https://www.oilshell.org/blog/2022/02/diagrams.html">narrow waists</a> I&#39;ve encountered recently. With a single line change, you can switch infrastructure providers within GitHub Actions. This benefits users by creating competitive pressure on runner providers to deliver superior service or risk losing customers. This stands in stark contrast to the traditional model where organizations found themselves trapped, facing days or weeks of migration effort that often resulted in vendor lock-in and price exploitation. Technology should prioritize user and organizational needs—not vendor profits.</p>
<h2 id="a-market-in-transition" tabindex="-1" class="marketing__blog_post__body__content__heading">
A Market in Transition<a href="#a-market-in-transition" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A Market in Transition"></a></h2>
<p>
The comprehensive mobile CI solution market is experiencing a gradual decline. The transition&#39;s pace depends on infrastructure providers&#39; ability to effectively market themselves within new ecosystems like mobile development. Additionally, this mental model shift—where teams return to GitHub Actions while paying only for infrastructure usage—will take time to permeate the industry. This approach isn&#39;t just superior; it&#39;s typically more cost-effective than traditional models where companies operate with constrained margins.</p>
<p>
I&#39;ve written previously about the importance of <a href="/blog/2025/03/11/own-your-automation">owning your automation</a>, and it bears repeating. While vendor lock-in is inevitable to some degree—even excellent developer experience creates switching costs—it exists on a spectrum. When companies recognize market decline without innovation capabilities (hello, innovator&#39;s dilemma), desperate attempts to increase lock-in often follow. Stay vigilant and maintain ownership of your automation. A key indicator of automation ownership is pipeline simplicity. Tools like <a href="/blog/2025/02/04/mise">Mise</a> enable predictable environment provisioning, while <a href="https://fastlane.tools/">Fastlane</a> or even bash scripts can handle automation logic. This agency is crucial in a rapidly evolving space, particularly as the infrastructure-as-a-service market accelerates. More providers will enter, prices will continue declining, and service quality will improve. If you&#39;re skeptical, I encourage you to explore Namespace&#39;s dashboard.</p>
<h2 id="an-emerging-landscape" tabindex="-1" class="marketing__blog_post__body__content__heading">
An Emerging Landscape<a href="#an-emerging-landscape" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to An Emerging Landscape"></a></h2>
<p>
This transformation naturally drives mobile CI companies to reinvent themselves through concepts like Mobile DevOps—evident in their expansion beyond traditional CI offerings. Suddenly, we find ourselves in a more competitive landscape, which I believe benefits the entire mobile ecosystem. The CI space had grown stagnant: everything revolved around pipelines, providers monopolized affordable macOS environments, and innovation stalled around familiar concepts (YAML pipelines, nightly releases, CI-driven deployments). The industry craves innovation, especially given the revolutionary changes in AI and agentic coding experiences.</p>
<p>
Every company is placing strategic bets on this emerging landscape. Some maintain narrow focus—perhaps on release management or launch time optimization. We initially maintained a narrow focus too, but we&#39;re gradually expanding for one compelling reason: AI is dramatically reducing software production costs and democratizing development. Yet current workflows often require indirection and complexity that diminish the space&#39;s appeal. We need to reintroduce magic to mobile development! Imagine agents that test your changes and provide runtime intelligence, or systems that identify flaky tests and automatically open PRs to resolve issues blocking your team.</p>
<p>
Is this Mobile DevOps? I don&#39;t believe so—that term has served its purpose. What’s emerging is something more modular and layered. We look to platforms like <a href="https://vercel.com/">Vercel</a> and <a href="https://expo.dev/">Expo</a> as our north stars, not just for their seamless repository integration and comprehensive tooling, but for how they abstract away infrastructure complexity while delivering a first-class developer experience.</p>
<p>
This is where the new model shines: you can now choose any macOS runner provider in an increasingly commoditized space, thanks to the “runs-on” revolution. The infrastructure layer becomes interchangeable, and on top of that, we (and others) can build a specialized layer that provides mobile-specific insights, mobile previews, and developer-centric features. Tuist is designed to work regardless of which runner provider you choose, ensuring you’re never locked in and always able to benefit from innovation at every layer.</p>
<p>
In this sense, the real transformation is about decoupling: the infrastructure layer is separated from the developer experience layer. This empowers teams to select the best underlying compute for their needs, while still enjoying a rich, mobile-first platform experience—on-the-go releases, preview sharing via simple links, and proactive notifications about potential test flakiness. This is the essence of the “runs-on” revolution, and it’s what sets this new era apart from the Mobile DevOps of the past.</p>
<h2 id="looking-forward" tabindex="-1" class="marketing__blog_post__body__content__heading">
Looking Forward<a href="#looking-forward" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Looking Forward"></a></h2>
<p>
The future holds tremendous promise, and this market transition represents the best possible outcome for our ecosystem. Organizations will simultaneously reduce costs and receive superior service, while infrastructure becomes more affordable and accessible, enabling companies like ours to compete alongside industry giants undergoing their own transformations. The result? The innovation our industry desperately needs.</p>
<p>
For established CI providers, this shift presents both challenges and opportunities. Those who recognize and adapt to this new paradigm—focusing on their unique value propositions while embracing the infrastructure-as-a-service model—will thrive. The key lies in understanding that the market isn&#39;t disappearing; it&#39;s evolving. Success will come to those who can navigate this transition while continuing to deliver exceptional value to their users.</p>
<p>
The mobile development landscape is ready for its next chapter. Are you?</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Developer experience wins from WWDC25 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Apple's WWDC25 brought exciting developer tooling updates: new UI testing capabilities, in-code playgrounds, explicit modules by default, and their own container CLI. Here's how we think about them at Tuist. ]]></summary>
      <link href="https://tuist.dev/blog/2025/06/10/wwdc"/>
      <id>https://tuist.dev/blog/2025/06/10/wwdc</id>
      <updated>Tue, 10 Jun 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Having slept on all the WWDC announcements and while drinking my first morning coffee, I think it&#39;s time to share a curated list of the announcements we&#39;re most excited about and how they relate to our plans for Tuist. Ready?</p>
<p>
What follows is a curated, non-exhaustive list in no particular order.</p>
<p>
<strong>We are developer tooling nerds, so expect the updates we&#39;re excited about to be focused on the developer experience.</strong></p>
<h2 id="new-testing-capabilities" tabindex="-1" class="marketing__blog_post__body__content__heading">
New testing capabilities<a href="#new-testing-capabilities" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to New testing capabilities"></a></h2>
<p>
In Xcode 26, Apple has invested heavily in tools for writing and debugging UI tests. From recording UI interactions and getting the code written for you, to built-in editor capabilities for adjusting the generated code—we think these new tools are amazing. They&#39;ve also added support for recording videos of your UI tests during execution, so when you see the test results on completion, you can more easily debug what happened. This is much better than just looking at logs or execution traces. I recommend watching the talk <a href="https://developer.apple.com/videos/play/wwdc2025/344">Record, replay, and review: UI automation with Xcode - WWDC25</a> to learn more about these improvements. Note that all these improvements only work with XCTest, but hopefully they&#39;ll make them work with Swift Testing soon.</p>
<p>
Additionally, they added an API that allows you to catch <code class="inline">fatalError()</code> and <code class="inline">precondition()</code> calls from your tests, plus <a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/testing/0009-attachments.md">an attachment</a> API so you can attach information that might be relevant later for debugging tests.</p>
<p>
We think these improvements are fantastic, and you might want to explore pairing their adoption with <a href="https://developer.apple.com/documentation/swift/tasklocal">Task Locals</a> to scope state to each test. This way, you can take advantage of all the cores in your Apple Silicon to increase test performance through parallelization.</p>
<p>
Having these capabilities is great for Tuist. While Apple focuses on improving their foundations and making them more capable, we go the extra mile by using those APIs to make them more accessible via the web. We make them even more useful by correlating them with information from other sources (like GitHub) and bringing insights close to where developers spend their time, like Slack. We&#39;ll soon extend our <a href="https://docs.tuist.dev/en/guides/develop/insights">insights</a> feature to include insights from your test runs, surfacing the most relevant information from your test results and giving you the option to download the result bundle and open it with Xcode if you need to dive deeper.</p>
<h2>
A new <a href="https://mastodon.social/@iKyle/114656391320509011">#playground</a> macro</h2>
<p>
With LLMs presenting developers with an opportunity to rethink how we develop, Apple has noticed the need for an isolated space within your project where you can play with your project&#39;s code building blocks without going through the scheme-based compilation cycle. Think of this as previews, but for non-UI code.</p>
<p>
Traditionally, SwiftUI previews have been known for being unreliable, especially in large modular projects with many implicit dependencies where the preview panel can&#39;t reliably build the part of the graph necessary for the preview to work. Will it be the same case for playgrounds? We&#39;ll see once people start using them.</p>
<p>
Our feeling is that with the default move to explicit modules and the introduction of a content addressable store (CAS) (more on this later), these are steps toward making SwiftUI previews more reliable, and potentially in-code playgrounds too.</p>
<h2 id="xcode-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Xcode improvements<a href="#xcode-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Xcode improvements"></a></h2>
<p>
Apple shipped many incremental improvements in Xcode. A few that caught our attention:</p>
<ul>
  <li>
They&#39;re tracking many more metrics from your production apps if users opt into them. They expanded the list of supported metrics and added recommendations based on what Apple considers a good baseline.  </li>
  <li>
Months ago, Apple unified and open-sourced the build system that powers Xcode and SwiftPM, taking the opportunity to make it extensible. While it&#39;s not very user-facing, users will benefit transitively through more reliability and performance since it eliminates the need to reconcile SwiftPM and Xcode&#39;s build systems (both use the same one now). This is great news for the ecosystem, and the best part is that it&#39;s open source.  </li>
  <li>
They&#39;re defaulting to explicit modules now, which should lead to faster and more reliable builds, and through CAS, optimizable builds in the future.  </li>
</ul>
<p>
Apple is taking steps in what we believe is the right direction and gives us ideas for how Tuist should evolve to augment the new capabilities of these tools.</p>
<p>
  <img src="/marketing/images/blog/2025/06/10/wwdc/explicit-modules.jpeg" alt="A screenshot of Apple&#39;s presentation that shows how the new explicit module feature translates into 3 build phases: scan, build modules, build source">
</p>
<h2 id="container" tabindex="-1" class="marketing__blog_post__body__content__heading">
Container<a href="#container" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Container"></a></h2>
<p>
Apple has released their own open-source CLI to run Linux containers on macOS: <a href="https://github.com/apple/container">container</a>. It&#39;s written in Swift and builds on another open-source project of theirs, <a href="https://github.com/apple/containerization">containerization</a>, which builds on Apple&#39;s virtualization framework. If you&#39;ve used Docker or Podman before, they serve similar roles—you can start Linux containers from images. However, unlike Docker, containerization uses Apple&#39;s virtualization framework. This provides stronger isolation, as each container has its own kernel, reducing the risk of kernel-level attacks.</p>
<p>
Thanks to their use of VIRTIO drivers, they can achieve fast boot times and low memory usage, making VMs nearly as lightweight as traditional containers.</p>
<p>
I can&#39;t help but wonder why Apple invested in their own open-source solution when we already have Docker and Podman. But I guess as Swift spreads to other ecosystems like web servers or Swift executables that run on Linux OSs, controlling the developer experience of using Swift in those environments at a lower level makes sense.</p>
<p>
If you want to give it a shot, you can install it and then run the following command to build your Swift package on Linux using Swift 6.1:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
container run --rm -v &quot;$(pwd)&quot;:/workspace -w /workspace swift:6.1 swift build    </shiki-highlight>
  </div>
</div>
<h2 id="content-addressable-store-(cas)" tabindex="-1" class="marketing__blog_post__body__content__heading">
Content Addressable Store (CAS)<a href="#content-addressable-store-(cas)" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Content Addressable Store (CAS)"></a></h2>
<p>
When Apple open-sourced their unified <a href="https://github.com/swiftlang/swift-build">build system</a>, we were excited to see Apple investing in a <a href="https://github.com/swiftlang/swift-build/tree/main/Sources/SWBCAS">content addressable store</a>. We thought we&#39;d see a bigger announcement this WWDC, but it was just a soft release, perhaps because it&#39;s not yet stable.</p>
<p>
You might not be familiar with <a href="https://en.wikipedia.org/wiki/Content-addressable_storage">the concept</a>, but you&#39;re probably familiar with the consequences of the build system not having it and doing everything through derived data: unreliable incremental builds and features like SwiftUI previews. A build system with a content addressable store works such that for build tasks, it can get a fingerprint knowing all the inputs and outputs of a build task. If the build system can assume it has all the information about inputs and outputs, then it can calculate a hash and look up the result of a previous build task by that hash. The problem is that due to how Xcode projects and the build system are designed, they&#39;re not fully hermetic and support implicit imports, which means files being built might depend on something the build system doesn&#39;t know about, causing the build system with CAS to fail compilation.</p>
<p>
So before we get there, we need to move to a hermetic world at the build system level with explicit modules. I believe this is why Apple has made explicit modules the default in Xcode 26. You can try to opt into CAS by setting the following build setting, but it failed for us in a recently-created project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
COMPILATION_CACHE_ENABLE_CACHING=YES    </shiki-highlight>
  </div>
</div>
<p>
We believe this is a multi-year effort, but the future looks bright because it&#39;ll bring not only stability but also native build-time optimizations by sharing those artifacts across environments. Sounds familiar? Yes! This is what <a href="https://bazel.build/">Bazel</a> does. At Tuist, we&#39;ll start investigating how we can hook into that system to provide the fastest latency possible, potentially partnering with some providers and enhancing those capabilities with the best and most actionable metrics to optimize projects further.</p>
<h2 id="small-bites" tabindex="-1" class="marketing__blog_post__body__content__heading">
Small bites<a href="#small-bites" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Small bites"></a></h2>
<ul>
  <li>
The Xcode editor <a href="https://mastodon.social/@jsq/114655965764298620">annotates</a> the end of compiler directives to show which directive they belong to.  </li>
  <li>
The attention to detail that Apple has put into Liquid Glass is quite impressive, and <a href="https://community.tuist.dev/t/tuists-take-on-the-wwdc/612/2">this is a testament to that</a>.  </li>
  <li>
Xcode download size <a href="https://developer.apple.com/videos/play/wwdc2025/247/">has decreased</a> by 24% and workspace loading performance has been boosted by 40%. So if you have a large workspace, this is a reason to be happy.  </li>
</ul>
<h2 id="things-we-theorized-about-that-didn't-happen" tabindex="-1" class="marketing__blog_post__body__content__heading">
Things we theorized about that didn&#39;t happen<a href="#things-we-theorized-about-that-didn't-happen" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Things we theorized about that didn't happen"></a></h2>
<p>
Last year we saw frequent git conflicts being mitigated with buildable folders, so we wondered if Apple would continue addressing long-lasting issues by finally settling on a user-facing graph format that&#39;s unified across apps and packages. Developers are pushing Swift packages to be that format, trying to run away from the inconveniences of Xcode projects. That push has manifested in Swift packages starting to look more like Xcode projects, but in a DSL that wasn&#39;t designed for that purpose—the format might suffer as a result.</p>
<p>
Part of me was expecting to see a decision there. I saw some people mentioning a <code class="inline">Project.swift</code> file, but it didn&#39;t happen. My bet is that before we get there, we need better sandboxing capabilities, perhaps a subset of Swift that can be evaluated quickly, and a migration path for people to start adopting it. With <a href="https://github.com/swiftlang/swift-build">swift-build</a> being open source, I think that&#39;s a natural next step.</p>
<p>
We also wondered if Apple would do anything in the area of developer productivity, and while we see signs of that, it&#39;s still too early. Their toolchain is becoming more capable, but the legacy of past decisions—like the design of derived data, which led to many projects accidentally building—is a hard place to move from. But it&#39;s slowly happening.</p>
<p>
Seeing these things being solved at a lower level would be great because we can focus our efforts on areas where Apple hasn&#39;t traditionally been good or shown interest—like making dev tools accessible via the web, or correlating their data with data from other places where developers spend time to provide new developer experiences that would be hard to imagine Apple building.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
There are many more improvements that span platforms and areas, so we recommend checking them out on the developer platform or in the app. We believe the ecosystem is more thriving than ever, developer tools keep getting better, and we couldn&#39;t be more excited to keep augmenting these capabilities with integrations, new insights, and optimizations to make teams more productive.</p>
<p>
<strong>This post has been written by a human, and its grammar has been edited by <a href="https://www.anthropic.com/claude/sonnet">Claude Sonnet 4</a></strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Open sourcing Noora for the web ]]></title>
      
      
      <author>
        <name><![CDATA[ Christoph Schmatzler ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We're open sourcing Noora for the web—a complete, accessible design system for Phoenix LiveView with Figma files and ready-to-use components. ]]></summary>
      <link href="https://tuist.dev/blog/2025/06/10/open-sourcing-noora-for-the-web"/>
      <id>https://tuist.dev/blog/2025/06/10/open-sourcing-noora-for-the-web</id>
      <updated>Tue, 10 Jun 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
We love open source - that&#39;s not a secret. A few months ago, we open sourced <a href="https://github.com/tuist/Noora">Noora</a>, our design system for building CLIs in Swift, which our own CLI is now built on. Today, we&#39;re extending Noora to the web: a complete design system for building web applications with Phoenix LiveView.</p>
<p>
Two months ago, we <a href="https://tuist.dev/blog/2025/04/17/meet-new-tuist">announced</a> the redesigned Tuist dashboard and today we are releasing the building blocks that we created to build it: a complete design system for building web applications with Phoenix LiveView, including all the Figma design files and the fully accessible components.</p>
<h2 id="building-blocks-for-liveview" tabindex="-1" class="marketing__blog_post__body__content__heading">
Building blocks for LiveView<a href="#building-blocks-for-liveview" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Building blocks for LiveView"></a></h2>
<p>
When we started building the new dashboard, we evaluated several ways to implement the beautiful designs from our designer <a href="https://www.asmitbm.me/">Asmit</a>.</p>
<p>
As a starter, our server is implemented in Elixir using Phoenix. All pages are built with Phoenix LiveView and therefore server-side rendered. This allows us to iterate much faster than if we had to deal with client-side state management, which is why we decided to build the new dashboard with LiveView as well.</p>
<p>
Using server-side rendering is amazing for us, but it also comes with some challenges when building a highly interactive user interface like our dashboard. We had a few important principles that we wanted to follow while bringing our design system to life:</p>
<ul>
  <li>
<strong>It needs to be accessible</strong>: We want our tools to be accessible to invite everyone to use our tools, benefit from them, and share ideas to make the product better every day.  </li>
  <li>
<strong>It needs to be keyboard-navigatable</strong>: Being developers ourselves, we use our keyboard a lot to navigate the tools we use every day, and we want to make sure that our tools feel great to use with the keyboard.  </li>
</ul>
<p>
Both of these are solved by <a href="https://react-spectrum.adobe.com/react-aria/index.html">so</a> <a href="https://radix-ui.com/">many</a> <a href="https://kobalte.dev/">different</a> <a href="https://headlessui.com/">libraries</a> in the JavaScript world, but there is a lack of good solutions for LiveView, while the bundled JavaScript functionality is not sufficient to meet our requirements.</p>
<ul>
  <li>
<strong>It needs to be as close to the web as possible</strong>: The web is designed to last. As a small team of four, we want to focus on building features rather than chasing breaking changes. Modern CSS has improved dramatically—we use plain CSS without post-processing. While we embrace web standards for JavaScript, we still bundle our code because loading external dependencies (like Zag) from CDNs within a library would require consumers to configure CSP headers and handle version management—complexity we want to avoid.  </li>
</ul>
<p>
In the end, we decided to build our design system on plain CSS while building our own hook system based on <a href="https://zagjs.com/">Zag</a>, a library of state machines for building UI components that is agnostic to what rendering framework is used. It has been amazing to work with, and I&#39;m happy to have our components be fully keyboard-controllable.</p>
<p>
The result is a complete set of LiveView components that handle focus management, ARIA attributes, and keyboard interactions out of the box. No more wrestling with other dependencies and hand-writing focus trapping logic.</p>
<h3 id="the-quick-start" tabindex="-1" class="marketing__blog_post__body__content__heading">
The quick start<a href="#the-quick-start" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The quick start"></a></h3>
<p>
For detailed setup instructions, check our full documentation on <a href="https://hexdocs.pm/noora/">HexDocs</a>, but here&#39;s a quick start to get you going if you just want to try it out. There&#39;s also a <a href="https://storybook.noora.tuist.dev/">Storybook</a> available to explore the components and their available properties.</p>
<ol>
  <li>
Add the dependency to your <code class="inline">mix.exs</code> file:  </li>
</ol>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
elixir    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="elixir">
defp deps do
  [
    {:noora, &quot;~&gt; 0.1.0&quot;}
  ]
end    </shiki-highlight>
  </div>
</div>
<ol start="2">
  <li>
Import the styles in your <code class="inline">app.css</code> file:  </li>
</ol>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
css    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="css">
@import &quot;noora/noora.css&quot;;    </shiki-highlight>
  </div>
</div>
<ol start="3">
  <li>
Add the JavaScript hook to your <code class="inline">app.js</code> file:  </li>
</ol>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
javascript    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="javascript">
import Noora from &quot;noora&quot;;

let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {
  // Your existing socket setup
  hooks: { ...Noora },
});    </shiki-highlight>
  </div>
</div>
<p>
That&#39;s it! You can now use the components in your LiveView templates. As a helper, we also expose a <code class="inline">use Noora</code> macro that automatically imports all components.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
html    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="html">
&lt;.button variant=&quot;primary&quot; label=&quot;Hello, Noora!&quot; /&gt;
&lt;.badge label=&quot;Passed&quot; color=&quot;success&quot; style=&quot;fill&quot; size=&quot;large&quot; /&gt;    </shiki-highlight>
  </div>
</div>
<h2 id="the-figma-files" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Figma files<a href="#the-figma-files" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Figma files"></a></h2>
<p>
  <img src="/marketing/images/blog/2025/06/10/open-sourcing-noora-for-the-web/preview.png" alt="Preview of components">
</p>
<p>
We&#39;re not just open sourcing code - we&#39;re releasing the entire design system, including the Figma files with all of our tokens, designs and examples. You can find them directly on <a href="https://www.figma.com/community/file/1512465864777652939">Figma</a>, ready to explore before installing Noora and building your website with it.</p>
<h2 id="what's-next?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next?<a href="#what's-next?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next?"></a></h2>
<p>
We are excited to release this first version. It&#39;s been in production for a while now, has received a lot of love and attention, and we are genuinely looking forward to seeing what you build with it. We will continue to push new components and updates to existing ones to power all of the new stuff we are working on, and are also welcoming contributions in the form of bug reports and pull requests.</p>
<p>
We will also update our <a href="https://noora.tuist.dev">Noora documentation page</a> which is currently focused on the CLI version of Noora to include the web version as well. This didn&#39;t quite make the cut for the initial release, but we will have it ready soon. We are also going to update the Storybook with more real-world examples from our own usage patterns building Tuist.</p>
<p>
Looking further into the future, we are keeping a close eye on what&#39;s possible with web components and how we can leverage them to make Noora for the web completely agnostic of where you use them, decoupling it from Elixir and LiveView and allowing other server-side frameworks such as <a href="https://vapor.codes/">Vapor</a> to use Noora as well.</p>
<h2 id="the-links,-all-in-one-place" tabindex="-1" class="marketing__blog_post__body__content__heading">
The links, all in one place<a href="#the-links,-all-in-one-place" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The links, all in one place"></a></h2>
<ul>
  <li>
<a href="https://github.com/tuist/Noora">GitHub</a>  </li>
  <li>
<a href="https://www.figma.com/community/file/1512465864777652939">Figma</a>  </li>
  <li>
<a href="https://hex.pm/packages/noora">Hex</a>  </li>
  <li>
<a href="https://hexdocs.pm/noora/">HexDocs</a>  </li>
  <li>
<a href="https://storybook.noora.tuist.dev/">Storybook</a>  </li>
</ul>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Building data-driven dev environments for Apple platforms ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Explore how Apple's proprietary Xcode formats prevent data-driven development decisions and how Tuist is building the missing infrastructure to unlock productivity insights. ]]></summary>
      <link href="https://tuist.dev/blog/2025/06/06/data-informed-decisions"/>
      <id>https://tuist.dev/blog/2025/06/06/data-informed-decisions</id>
      <updated>Fri, 06 Jun 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<strong>This blog post will be valuable for people interested in understanding how they can use data to improve their development environments, and learn how Tuist is building the infrastructure to enable data-driven decisions.</strong></p>
<p>
You might have heard of the concept of data-informed decisions—the idea that you back your decisions using data. The more and better data you have, the better your decisions can be, and this principle applies to developer environments too.</p>
<p>
Many disciplines in the tech industry follow this approach: product, marketing, sales, and even engineering in production systems. However, some disciplines and domains have traditionally refrained from backing decisions with data, and app development productivity is one of those. Why, you might ask? In this blog post, I&#39;d like to distill that for you and share examples of how having the right data can help you take a different approach to your development setup.</p>
<h2 id="the-problem:-xcode's-proprietary-ecosystem" tabindex="-1" class="marketing__blog_post__body__content__heading">
The problem: Xcode&#39;s proprietary ecosystem<a href="#the-problem:-xcode's-proprietary-ecosystem" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The problem: Xcode's proprietary ecosystem"></a></h2>
<p>
Have you ever heard of the concept of <a href="https://www.oilshell.org/blog/2022/02/diagrams.html">narrow waist</a>? It&#39;s the idea that a concept, interface, or protocol solves an interoperability problem. TCP/IP is a narrow waist between the application layer and the transport layer. Shipping containers are the narrow waist between goods and transport mechanisms.</p>
<p>
Often, these narrow waists are created by data formats like <a href="https://en.wikipedia.org/wiki/Markdown">Markdown</a>, which many editors and tools can interact with. When you choose Markdown, you know it&#39;s synonymous with having access to an ecosystem of tools that can work with it.</p>
<p>
But Apple created their own ecosystem. Even though they&#39;re not the only ones building tools for developers—like build systems or test runners—they refused to adopt and, in some cases, evolve existing standards. Instead, they leaned into Xcode-scoped proprietary formats. These formats were optimized to be interacted with from Xcode, and their usage outside of that context required extensive reverse engineering. This is something we had to do with <a href="https://github.com/tuist/xcodeproj">tuist/xcodeproj</a>, and Spotify had to do with <a href="https://github.com/MobileNativeFoundation/XCLogParser">XCLogParser</a>.</p>
<p>
<strong>When you have to reverse-engineer an undocumented format, the incentives to build a narrow waist are minimal.</strong> But by not building it, you prevent developers from having access to an ecosystem of tools. As a consequence, you create a strong dependency on Apple&#39;s investment in developer tools. Sure, they make amazing tools, but other people do too—perhaps you don&#39;t need to build everything yourself.</p>
<p>
The result is that everything happens within Xcode. Any state, whether it&#39;s the result of a build or tests, doesn&#39;t &quot;escape&quot; that environment.</p>
<h2 id="the-infrastructure-challenge:-where-to-store-and-process-data" tabindex="-1" class="marketing__blog_post__body__content__heading">
The infrastructure challenge: where to store and process data<a href="#the-infrastructure-challenge:-where-to-store-and-process-data" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The infrastructure challenge: where to store and process data"></a></h2>
<p>
Let&#39;s assume you&#39;ve gained access to the data. You&#39;ve hacked your way through Xcode projects, used community tools to convert the format into a JSON payload, and you&#39;re ready to use it. The next natural question is: where do I place the data, and what do I do with it?</p>
<p>
Storing it locally wouldn&#39;t be useful enough because you&#39;d only be able to see your own data and compare how it changes over time within your environment. As we&#39;ll see later, there are many interesting insights we can derive once we make the data escape an environment. So you need a place to store the data and a publicly accessible API to push it to. You need a server.</p>
<p>
At this point, you&#39;ll most likely need to sit down with a backend or infrastructure engineer from your company to spin up a data-ingestion pipeline or an instance of <a href="https://github.com/spotify/XCMetrics">XCMetrics</a>. But as I said earlier, the incentives to maintain narrow waists or tools that work with proprietary formats are minimal. With Spotify no longer using Xcode&#39;s build system, the project is no longer actively maintained. So chances are you give up.</p>
<p>
Your project will continue growing. Every year, you&#39;ll pitch to your leadership about getting faster Apple Silicon—which your engineers and Apple will be happy about—and hope that things are just fine.</p>
<p>
But even though you can&#39;t directly observe your dev environments, people talk about their feelings in private or group conversations. They joke about those flaky tests continuously making PRs red and requiring retries, or SwiftUI previews breaking again in the most recent Xcode version, or having to frequently delete derived data every time they change between branches. If you&#39;ve been on a team working on an Xcode project, I&#39;m sure you&#39;ve been in one of these conversations.</p>
<p>
Sooner or later, the unproductivity becomes so obvious that you find yourself in a desperate leadership decision, which typically ranges from adopting React Native or Flutter to asking the most senior people on the team to explore new build systems.</p>
<h2 id="the-power-of-data:-insights-you-can-gain" tabindex="-1" class="marketing__blog_post__body__content__heading">
The power of data: insights you can gain<a href="#the-power-of-data:-insights-you-can-gain" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The power of data: insights you can gain"></a></h2>
<p>
Before we dive into what Tuist is doing to change the state of things, I think it&#39;s important to stop for a second and reflect on which questions we can get answered once we collect and process the data.</p>
<p>
The most obvious metric is <strong>build times</strong>, and it&#39;s the one organizations are most interested in because it has the highest impact on productivity. If you get the build time per scheme, target, and file, you can see not only how they evolve over time but also how different decisions impact build time. For example, Apple Silicon has multiple cores, but their presence doesn&#39;t mean they&#39;re being used as effectively as possible. You might need to make changes in your graph or enable new Xcode features such as explicit modules to allow the build system to parallelize more.</p>
<p>
What about how frequently people clean derived data, which translates to clean builds? If people are cleaning derived data too frequently, this negatively affects productivity, and it&#39;s important to understand why people clean in the first place. Are they getting an error they don&#39;t understand? Was an Xcode feature not working as expected?</p>
<p>
Another metric directly connected to productivity is <strong>flakiness</strong>. If tests are flaky, people need to retry CI in their PRs, and whenever they do, they&#39;re increasing the time it takes to get their changes merged. Detecting whether a test is flaky requires storing two metrics for each uniquely identified test: a hash and a status. If, given the same hash, we get different results, we might consider the test flaky. By persisting this information, you can have a flakiness scoreboard so you know which tests are causing the most harm to your dev environment and prioritize fixing them.</p>
<p>
What if you invest in new laptops, a new version of Xcode or Swift, or introduce a caching system like Tuist&#39;s? Then you can see the impact it&#39;s had on your team and do some mathematics to know if the investment was worth it. Without data, none of this is possible.</p>
<h2 id="building-the-missing-infrastructure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Building the missing infrastructure<a href="#building-the-missing-infrastructure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Building the missing infrastructure"></a></h2>
<p>
We can&#39;t influence Apple to give up on proprietary formats and build more narrow waists. We&#39;ve seen it&#39;s costly for the community, but unless there&#39;s a mindset change, it&#39;s very unlikely to happen.</p>
<p>
What we&#39;re doing with Tuist is trying to map those proprietary formats into standards that people can build tools upon. We did that with <a href="https://github.com/tuist/xcodeproj">XcodeProj</a> to read, update, and write Xcode projects, <a href="https://github.com/tuist/XcodeGraph">XcodeGraph</a> to have an in-memory representation of a project that&#39;s much nicer to work with than vanilla Xcode projects, and <a href="https://github.com/tuist/Rosalind">Rosalind</a>, which generates a schema with the internal structure of an Apple bundle. In other words, we build narrow waists in the Apple ecosystem so that others can build tools and come up with new ideas and improvements to make everyone&#39;s development experience better.</p>
<p>
Once you have a narrow waist you can build features that are easy to adopt, and this is where Tuist comes in: we package the infrastructure management and make that data useful and actionable into a server product that has a strong focus on developer experience. It&#39;s plug-and-play. We also provide an API and soon data-ingestion capabilities so that you can build your own apps upon Tuist, or extract data from your projects into your data pipelines.</p>
<p>
Remember XCMetrics that I mentioned before? Unlike it, you don&#39;t need to deploy anything. You sign up, create a project, <a href="/blog/2025/06/05/build-insights">make a one-line change in your project, and you&#39;re good to go.</a></p>
<p>
Perhaps Apple will change their strategy and embrace industry standards like <a href="https://opentelemetry.io/">OpenTelemetry</a>. If that ever happens, we&#39;ll be the first ones celebrating because it&#39;ll be a win for the entire ecosystem. But until that happens, we think the ecosystem and teams need the narrow waists that we&#39;re building. It&#39;s important that we do so while building an incentive system to keep giving teams those tools to improve their workflows.</p>
<p>
<strong>This post was written by a human and its grammar reviewed with Claude 4 Sonnet.</strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Measure, analyze, and improve your build times with Tuist Build Insights ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Get Xcode build analytics for local and CI builds with Tuist Build Insights. ]]></summary>
      <link href="https://tuist.dev/blog/2025/06/05/build-insights"/>
      <id>https://tuist.dev/blog/2025/06/05/build-insights</id>
      <updated>Thu, 05 Jun 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Sooner or later in the lifecycle of any software project, you&#39;ll find yourself needing to iterate on its setup and tools to ensure your <a href="/blog/2025/02/28/momentum">momentum</a> doesn’t fade. We often refer to this as <em>scaling development</em>. It’s inevitable. The tools and practices that once worked start to break down as the project grows larger, with multiple modules, complex dependencies, a team of contributors working in parallel, and a growing test suite ensuring reliability.</p>
<p>
Among all the factors at play, one of the most critical—because it directly affects the feedback loop—is <strong>build time</strong>. Build performance tends to degrade as projects grow, often due to unreliable incremental builds, derived data resets, or changes in the project graph or toolchain (e.g., explicit modules) that can impact parallelization. Understanding build times is essential for making optimizations and improving development velocity—but doing so is far from straightforward.</p>
<p>
While the toolchain provides data—like the <a href="https://developer.apple.com/videos/play/wwdc2022/110364/?time=397">build graph</a>—raw output alone isn’t enough. First, you need to make that data accessible. Second, data that’s isolated in time or scope may not reveal much. But if you persist it over time and correlate it with the team activity—tying it back to specific developers or workflows—then meaningful insights start to emerge.</p>
<p>
At Tuist, we don’t want to just help teams optimize workflows through better tooling; we also want to empower them with actionable data to make smarter decisions—whether to boost productivity or improve developer happiness.</p>
<p>
That’s why we’re thrilled to introduce <a href="https://docs.tuist.dev/en/guides/develop/insights"><strong>Tuist Build Insights</strong></a>: Xcode build analytics for collecting and analyzing build data across any environment—including local development.</p>
<p>
👉 If you’d like to see it in action, check out the video below:</p>
<iframe title="Tuist Build Insights" width="560" height="315" src="https://videos.tuist.dev/videos/embed/fABmyCEkN7vT1TU7n464LM" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="integration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Integration<a href="#integration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Integration"></a></h2>
<p>
To get started with build insights, you will need a <a href="https://docs.tuist.dev/en/server/introduction/accounts-and-projects">Tuist account and a project</a>. The best way to get started is to use our <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist">CLI</a> and run the <code class="inline">tuist init</code> command.</p>
<p>
Once you authenticate, you will need to add a <code class="inline">tuist inspect build</code> command in your Xcode scheme build post-action – unless you use <a href="https://docs.tuist.dev/en/guides/develop/projects">generated projects</a>, in which case we generate the post-action for you:</p>
<p>
  <img src="/marketing/images/blog/2025/06/05/build-insights/inspect-build-scheme-post-action.png" alt="Screenshot of how to set up an Xcode post action for build insights">
</p>
<p>
For more details how to set up build insights, head over to our <a href="https://docs.tuist.dev/en/guides/develop/insights">docs</a>.</p>
<h2 id="inspecting-individual-builds" tabindex="-1" class="marketing__blog_post__body__content__heading">
Inspecting individual builds<a href="#inspecting-individual-builds" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Inspecting individual builds"></a></h2>
<p>
After you include <code class="inline">tuist inspect build</code> in your Xcode build post-action, build your app in Xcode and once the build is finished, you will see the build directly in your project dashboard.</p>
<p>
When you go to a given build detail, you will see something like this:</p>
<img alt="Screenshot of a build detail" style="max-width: 70vw" src="/marketing/images/blog/2025/06/05/build-insights/inspected-build.png">
<p>
Let&#39;s break down what&#39;s included in the build detail:</p>
<ul>
  <li>
Metadata such as git branch, whether a build was <strong>clean or incremental</strong>, build duration, Xcode version, and more.  </li>
  <li>
Errors and warnings: Listed errors and warnings flagged during the build. You get a readable message along with a link directly to the source file in GitHub. No need to parse the obscure <code class="inline">xcodebuild</code> output anymore from your CI logs.  </li>
  <li>
Module and file breakdown: Ran into a long build? Tuist now lists out how long Xcode took to build individual modules and files, so you can focus on the outliers.  </li>
</ul>
<p>
The build detail comes especially handy when you need to inspect a build that occurred in a different environment than yours – such as from the CI – or when analyzing build performance of a particular build. No need to upload and download <code class="inline">.xcresult</code> bundles anymore. What&#39;s more, you can easily send a link to your colleagues, so they can inspect the build themselves.</p>
<p>
However, build insights are not limited to inspecting individual builds. Where this feature really shines is when the data is analyzed <strong>over time</strong>. Something you can&#39;t get with Xcode.</p>
<h2 id="tracking-builds" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tracking builds<a href="#tracking-builds" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tracking builds"></a></h2>
<p>
Especially in larger organizations, having the data to assess the health of the developer environment is crucial to ensure developers are not hindered by slow builds. While organizations usually track the duration of CI pipelines, they often lack insights into the local developer environment. And on the CI, the numbers can be often misleading since the measurements are usually bundled with the rest of the pipeline.</p>
<p>
Tuist helps you to answer questions such as:</p>
<ul>
  <li>
How often do engineers run clean builds?  </li>
  <li>
How long does it typically take to build the app on incremental builds?  </li>
  <li>
How does the build time vary between different Xcode versions and devices?  </li>
</ul>
<p>
All of these questions, you will be able to answer by going to the &quot;Builds&quot; page in the Tuist dashboard:</p>
<img alt="Screenshot of a build page" style="max-width: 70vw" src="/marketing/images/blog/2025/06/05/build-insights/builds-overview.png">
<p>
In the &quot;Builds&quot; page, you have access to filters filters such as:</p>
<ul>
  <li>
Scheme  </li>
  <li>
Build – incremental or clean  </li>
  <li>
Environment – local or CI  </li>
</ul>
<p>
You can use these filters to powerfully slice the data, like getting the number of local <em>clean</em> builds that occurred in the last 30 days, along with the average build time.</p>
<p>
Do you want to play with an actual dashboard? Our Tuist dashboard is open for anyone, so you can see the build analytics that we track when working on the Tuist CLI and the <a href="https://community.tuist.dev/t/kicking-off-work-on-the-tuist-ios-app/570">upcoming iOS app</a>: <a href="https://tuist.dev/tuist/tuist/builds">https://tuist.dev/tuist/tuist/builds</a></p>
<h2 id="wrapping-up" tabindex="-1" class="marketing__blog_post__body__content__heading">
Wrapping up<a href="#wrapping-up" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Wrapping up"></a></h2>
<p>
Tuist build insights is a powerful tool to take Xcode&#39;s data, make it readily available in your browser, and analyze the data over time to simplify inspecting individual builds in arbitrary environments <em>and</em> to understand how productive your developer environment.</p>
<p>
How are we going to improve build insights further?</p>
<p>
We will:</p>
<ul>
  <li>
Include a link to builds from your CI workflow in the <a href="https://github.com/marketplace/tuist">GitHub Tuist report</a>  </li>
  <li>
Add deeper analytics to help you surface areas of improvement, such as adding suggestions for which module to split to optimize the parallelization of your build  </li>
  <li>
Couple the build data with <a href="https://docs.tuist.dev/en/guides/develop/cache">binary cache optimizations</a>  </li>
</ul>
<p>
Sounds exciting? Take this feature for a spin and let us know your feedback or ideas for how to improve build insights further 💜</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Building a business around Tuist ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Our lessons building a dev tools business: community focus, human-centered marketing, technological pragmatism, and creating sustainable innovation. ]]></summary>
      <link href="https://tuist.dev/blog/2025/05/20/business-around-tuist"/>
      <id>https://tuist.dev/blog/2025/05/20/business-around-tuist</id>
      <updated>Tue, 20 May 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<strong>This blog post will be valuable to those interested in the evolution of Tuist, as well as to individuals starting their own business—whether as indie developers or as a company.</strong></p>
<p>
In October 2023, <a href="https://marekfort.me/">Marek</a> and I agreed we&#39;d build a business to fund the development of Tuist and lay the financial groundwork needed to work full-time on what we like the most: crafting developer experiences for app developers and building a community who would join us in that effort.</p>
<p>
At the time, we had the community and a CLI that teams loved and used every day. We had experience at <a href="https://shopify.com">Shopify</a> building solutions for app developers, from tools like tophat, <a href="https://shopify.engineering/mobile-release-engineering-scale-shipit-mobile#">Shipit Mobile</a>, and <a href="https://shopify.engineering/mobile-release-engineering-scale-shipit-mobile#">Mac infrastructure</a>, to building runtime libraries for <a href="https://shopify.github.io/flash-list/">React Native</a>. We had the necessary ingredients to transform Tuist into a platform to help teams build better apps faster. We only lacked one experience: business.</p>
<p>
We&#39;ll admit it felt intimidating at first, but we were so passionate about what we wanted to achieve that we threw ourselves into understanding and navigating what it takes to get a business off the ground. Since then, we&#39;ve learned a lot—sometimes by accident, other times by reading—but regardless, we always tried to follow our instinct and did what we believed was best for the project, its community, and what aligned most closely with the type of company we wanted to build.</p>
<p>
What follows is a non-exhaustive list of our learnings that you might find useful if you are transitioning or considering leveraging your development skills to build your own company, either as an indie developer or as a small company. Remember that every company is different, so what worked for us might not work for you. If we had the chance again, we&#39;d absolutely do it again, because regardless of the challenges and the many ups and downs that come with it, it&#39;s extremely rewarding being able to create an environment where people can show up and help advance a certain ecosystem. Let&#39;s dive right in.</p>
<h2 id="from-collaboration-to-competition" tabindex="-1" class="marketing__blog_post__body__content__heading">
From collaboration to competition<a href="#from-collaboration-to-competition" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to From collaboration to competition"></a></h2>
<p>
Many people associate gratis with open source. Tuist was both, which is very inviting to contributions, collaboration, and also to donations. Once you build the brand, the project can be the catalyst for other brands. Being associated with open source and recognized community projects is attractive.</p>
<p>
But things change when you break the &quot;open means gratis&quot; mental model. You go from being something others want to be associated with to something that has the potential to become a competitor, so dynamics naturally change.</p>
<p>
And there&#39;s something unique to this kind of competition. It&#39;s usually a competitor with limited financial capital but with <strong>high social and human capital</strong>. This is abstract and hard to measure, but social capital can truly make the difference between thriving or not, and this is core to the way we shaped and continue to shape Tuist. Our interactions with people go beyond &quot;selling,&quot; &quot;marketing,&quot; or &quot;supporting.&quot; We give our hands to everyone. We collaborate with the people who show up. We share how we see the ecosystem and tell them what we are doing to get to a better position. We do so without expecting anything in return, which naturally builds unique momentum and value.</p>
<blockquote>
  <p>
We like to say that we are a tiny fish with little financial capital in an ocean of whales, but with human capital that can move mountains.  </p>
</blockquote>
<p>
We&#39;ve seen companies evolving their relationships with us, and we&#39;ll continue to see that, but we believe that&#39;s a natural part of the process. We&#39;re embracing it as a positive sign that we are on the right path to having an impact in the ecosystem. And to be honest with you, being able to do so with little capital is exciting because it brings out the most creative and human versions of ourselves.</p>
<h2 id="about-markets" tabindex="-1" class="marketing__blog_post__body__content__heading">
About markets<a href="#about-markets" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to About markets"></a></h2>
<p>
Building a company has taught us a lot about markets and business models. For us, we just want to have fun without being too worried about how to fund being able to do this full-time. <strong>We believe financial success is a consequence of having an environment where people can craft something for fun, not something easily achievable if you have it as your main goal.</strong></p>
<p>
The reality is that it&#39;s the goal for many companies, often because there&#39;s a set of hidden incentives beyond the company, and this leads to a market-based perception of ecosystems. Let us unfold for you the mental model that we&#39;ve formed.</p>
<p>
Ecosystems are markets—groups of people or companies that can be your customers. The larger the market, the better, and companies will do their best to capture most of it. Having a single company in a market is not good because innovation stagnates, though companies often prefer to be the only ones. Once they are in this dominant position, they can roll out practices that no one can challenge.</p>
<p>
Because markets invite competition, companies design products to create vendor lock-in. Some do it through ecosystems and social capital. Why don&#39;t you leave <a href="https://github.com">GitHub</a>? Because your developer CV is there. You get the idea... At some point, they reach a ceiling. They keep raising capital and making promises that they can break that ceiling through diversifying their offering, but then they force the product in ways that consumers can feel. At the same time, other players join the space. Those players can get capital easily because it&#39;s a known market, and then they try to push the prices down and attract customers through cheaper prices. Then, if the vendor lock-in is not effective, customers move on.</p>
<p>
At the same time, software commoditizes through open source, which means what was once your competitive asset is no longer one. As we learned through Tuist, once you build an open-source commodity and steward it, it becomes more attractive for the market.</p>
<p>
We think CI is a good example of this. It&#39;s a highly commoditized space. GitHub and <a href="https://gitlab.com">GitLab</a> changed the space by not only building CI into the Git forges, which gives them a unique development experience advantage, but designed it in a way that you can bring your runners and shift the cost to you. Then many companies emerged to provide those runners. They first built on existing cloud providers, and then they rolled out their own hardware. But once the market becomes very saturated, nothing prevents a company like <a href="https://aws.amazon.com">AWS</a> or <a href="https://www.cloudflare.com/">Cloudflare</a> from providing those runners for you because doing it reliably and fast is indeed their strength. You can&#39;t compete with AWS or Cloudflare providing containers close to where you need them because that&#39;s a muscle that they&#39;ve built for years.</p>
<p>
What does this all mean? That you need to know well what differentiates you. In the context of CI, for instance, you might have noticed that some companies try to offer more than just pipelines, environments, and build logs. <a href="https://buildkite.com">Buildkite</a>, for example, is placing a strong focus on building a top-notch product.</p>
<p>
For Tuist, we had to decide what our strength would be. There are not that many options in the dev productivity and app quality space for app developers, and Apple could solve some of the problems that we are solving, so what are we going to do differently to stay relevant and continue thriving? In our case, we decided that we&#39;d focus on the following things:</p>
<ul>
  <li>
<strong>Community</strong>: We&#39;ll continue building on open source, hence why our long-term plans are to open source everything, and create ecosystems of extensions for the toolchain.  </li>
  <li>
<strong>Developer experience</strong>: We want to build a product that&#39;s a joy to use thanks to our attention to detail. Sounds familiar? Attention to detail is what makes Apple products stand out, and it&#39;s the reason why we&#39;ve built a design system for our CLI and dashboard, Noora. Top-notch experiences are not an afterthought.  </li>
  <li>
<strong>Innovation</strong>: We should thrive on innovation. There are many workflows that are not possible in app development, and others that feel broken. Why aren&#39;t we able to get a preview by tapping a button? And why are releases still triggered from a CI pipeline? We need answers for these questions. Innovation requires creating a culture where new ideas are embraced and given the time, space, and love so they can emerge.  </li>
</ul>
<p>
These are the traits that we see making us unique in our space. Now, what&#39;s our space? That&#39;s a good question... By saying you belong to a particular market, everyone can immediately understand what you&#39;re all about. &quot;I do CI,&quot; or &quot;I do analytics...&quot; But we don&#39;t fit into any of the pre-established markets. We would say we are creating a new one, but we don&#39;t like the idea of markets either because they constrain what you do. We see ourselves as something more fluid. We solve problems and challenges that we think need a solution or a better one, and sometimes that means we&#39;ll step into other domains. Are previews the same as nightly builds? They are builds, but closer to where collaboration happens. Will we do CI? We&#39;ll figure out how to provision runners for some features, and since that&#39;s a base step for CI, we&#39;ll provide runners too. CI has already been solved by GitHub. These are just some examples. The core element around which everything gravitates is &quot;apps&quot;—first in the context of Apple ecosystem, which we know well, and potentially exploring others once we feel the time is right.</p>
<h2 id="why-would-anyone-pay-for-this?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why would anyone pay for this?<a href="#why-would-anyone-pay-for-this?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why would anyone pay for this?"></a></h2>
<p>
Providing a solution to a problem is not enough. First, the shape of your solution needs to be something people are used to paying for. Tuist started as a CLI. Trying to charge money for a CLI? Not a great idea. You typically don&#39;t pay for a CLI. This is a mental model that would take a tremendous effort to change.</p>
<p>
A server? That&#39;s a different story. We&#39;d pay for a solution on a server. Preferably, we&#39;d be ok with being the product to get it for free, but if they ask us for money for a server solution whose value we perceive, we&#39;ll pay for it.</p>
<p>
That meant strategically that we had to focus on problems whose solutions require a server. Moreover, we agreed we&#39;d do so following a model where any client-side technology would be open source and free of charge, and the server would augment it to provide different types of insights. Take, for instance, running tests. Running a test suite just tells you what passed and failed, and how long it took. Store that information over time (in a server database) along with a fingerprint that captures whether it changes or not, and you&#39;ve got a solution to detect flakiness. We made an exception to this rule which we aim to phase out once we can secure the business: cache.</p>
<p>
But we don&#39;t want to end here. Our server is closed source, but long-term we want everything to be open. But if we open everything, what do we charge for, right? We are still figuring out what the right model will be, but it&#39;ll most likely be a mix of paying for our hosting and a very small subset of features being under a slightly restrictive license to support contributions from larger enterprises for control over the platform. Most of our user base will be able to self-host if they want, as long as they are okay with the responsibilities that come with it. Our hosted instance will come with reliability, updates, speed, security, and support to help you focus on what matters. Many companies in the space try to maximize revenue from everyone, hence the classic &quot;contact sales&quot; or &quot;check this demo&quot; approach to products. We consider that to be inaccessible and hindering to innovation, so we want to take a different approach. Time will allow us to do that.</p>
<h2 id="mental-models" tabindex="-1" class="marketing__blog_post__body__content__heading">
Mental models<a href="#mental-models" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Mental models"></a></h2>
<p>
Once people build an idea of what you are, it takes an enormous amount of effort to change. For many people, we are still an Xcode project generator. For another good portion of users, we are still just solving frequent merge conflicts. Many haven&#39;t realized that most of our features work with any Xcode projects, so you don&#39;t need a generated project. We&#39;ll continue to improve and support generated projects for as long as modularization continues to be complex within Xcode and there are no good alternatives.</p>
<p>
This transition that we mentioned before—from a pure CLI solution to an ecosystem of solutions with a server at its core—came with a transformation of the product that we need to socialize. And believe us, this takes time and a lot of reminding about how we are evolving and how we see the space. We do that through our blog posts, videos, and content in various social channels. It never feels like enough, but it&#39;s remarkable how solidified some models can get in people&#39;s heads.</p>
<p>
This not only applies to the shape of the product but to people&#39;s understanding of a problem space. They are so attached to a particular established solution that they forgot what brought them to the solution in the first place. It has a name: cargo culting. And similarly, influencing it takes time and a lot of energy. To give you an example, many are still using <a href="https://github.com/fastlane">Fastlane</a>&#39;s abstractions for building projects. Some might not be needed—they could just be an <code class="inline">xcodebuild</code> invocation from a bash script—and if you mention this idea, they look as if you were telling them to replace their build system. Moreover, many of these things happen because of social effects. We humans are social species, so trying to use logic in such a setup is a recipe for frustration. For example, we continue to evangelize the idea that SwiftPM is not always the best solution to model a project if you want a great DX for your team. Often, this feels like sending messages into a void, but sooner or later, people will be present and recognize that pain and will be able to connect it with the many times we talked about how challenging that approach can be. You won&#39;t believe this, but we&#39;ve seen teams going from Tuist to SwiftPM and back to Tuist. We are the first ones to believe that if there&#39;s an official solution that works great, you should adopt it, but if there&#39;s not, we are honest about it.</p>
<p>
Another learning is that <strong>people iterate on their mental models incrementally.</strong> In other words, they need new ideas to be connected with existing ones. For example, if you are suggesting <a href="https://mise.jdx.dev/">Mise</a> as an installation tool, you need to connect it with <a href="https://brew.sh">Homebrew</a>, which many people are familiar with, and explain how it&#39;s more suitable. Or <a href="https://docs.tuist.dev/en/guides/features/previews">previews</a>, which many people want to connect with nightly builds, which they are most familiar with. So business-wise, you need to find a good balance between pushing innovation while integrating that with the tools and mental models of people. Quite a challenge, isn&#39;t it?</p>
<h2 id="security" tabindex="-1" class="marketing__blog_post__body__content__heading">
Security<a href="#security" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Security"></a></h2>
<p>
When projects are gratis and open source, companies&#39; security concerns are few to none, even though risks exist. But a company that offers paid solutions changes everything. Suddenly, security becomes a priority. We had to go through the process of being <a href="/blog/2025/04/03/soc2">SOC 2 certified</a>, performed penetration tests, and found ourselves in extensive processes with security teams going through checklists of questions.</p>
<p>
We care about security, and going through the process helped us improve the overall security of the company, but many aspects felt disproportionate.</p>
<p>
First, the process can feel like a checklist where checking off items doesn&#39;t necessarily mean you are safer. It&#39;s more about making yourself liable through your proofs, such that in case something happens, there&#39;s someone responsible. The way we see it is that you build a liability chain: customer &gt; auditor &gt; company. And if something goes wrong, well, these things happen because humans make mistakes, so you&#39;d better have insurance. Throughout the process, there were many times when we felt the approach was more procedural than substantive. And it doesn&#39;t matter if you just deal with low-sensitivity data, as is the case for Tuist, where we store information and binaries that are already in the apps that end up being shipped to the App Store. The process is the same for you, a small company that&#39;s just getting started, or a company with thousands of employees and in-house departments. And you sadly can&#39;t skip this if you want to convert customers.</p>
<h2 id="sales" tabindex="-1" class="marketing__blog_post__body__content__heading">
Sales<a href="#sales" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Sales"></a></h2>
<p>
Our only experience with sales was when I was younger and worked at family cafes selling coffees and churros. We guess this would be our version of &quot;it all started in a garage.&quot; Customers came, and they knew what they wanted. We provided them with a great product and a very human service, and they most likely came back and told others about it. It seemed simple, and most of what we learned there applies to selling software too. <strong>We are humans at the end of the day.</strong></p>
<p>
Through Tuist, we learned a few things in the area of sales. First, many of the things that you read out there might not work for you because every market is different. So we learned by trial and error. We tried to send emails—the sales lingo for this action is &quot;cold outreaches.&quot; Developers, our target, don&#39;t typically respond well to that. Developers like to build and avoid bureaucracy. They don&#39;t like to see an email in their inbox that says, &quot;Hey! I want to sell you this product.&quot; They dislike going through procurement processes so much that they can go as far as building a solution themselves or working around your system. Not everyone is like that, but you can see a pattern. Developers won&#39;t make the final purchase decision—that&#39;s more of a manager or director responsibility—but they are the ones who can influence the decision, so understanding the psychology is crucial. We are developers ourselves, so we have a good sense of what we&#39;d love to see.</p>
<p>
There are different approaches to reaching developers. We&#39;ve seen some companies applying techniques that connect to very basic emotions through their solutions. If you&#39;ve ever been sold insurance, you know what we&#39;re talking about... Fear is in everyone; it&#39;s our tool for survival. And if we say that by not using our tool, your business might not be going as well as you&#39;d like it to go—there you go, the fear of failing. Who likes that? Even if the connection between the two is tenuous, one thing we learned is that in business, many approaches are possible. Another approach we&#39;ve seen consists of leveraging our social traits. We, as humans, tend to compare ourselves with each other. In the real world, you can compare your salary, your net worth, your cars, your iPhones... But in the software world, you need to come up with something else, and then you can even build your marketing on it. We prefer not to take that route.</p>
<p>
So, with the quick tools out of the equation, how did we manage to get people to pay for Tuist? We focused on solving concerns that we noticed large companies have, like unproductive development environments, and solved them the best way we could, with a product that&#39;s very enticing to use. Apple solved people&#39;s needs to stay connected, as did Android, but they focused on solving it in the most beautiful way possible. That&#39;s similar to what we are trying to do. When you use Tuist, the value and the perceived value need to be as high as they can be—so high that you are inclined to pay for it if we ask for it and that you tell others about it. Like, &quot;Hey! I used Tuist&#39;s cache, and now I have this amazing dashboard that helps me make decisions. Until that point, I was on the verge of having to transition my entire suite to React Native because leadership was questioning our ability to deliver.&quot;</p>
<p>
What&#39;s key is that once the developer is convinced Tuist can be the solution to their problems, the process to witnessing the solution with their project needs to be as short as possible. They&#39;ll most likely do this in some spare time that they have here and there, so if the process is quite long, they&#39;ll most likely drop it, and you&#39;ll never be able to sell anything. For that reason, we invested in a new &quot;get started&quot; workflow that takes you through all the necessary steps, including creating an account. We are also making most of Tuist&#39;s features work with Xcode projects so that the changes you need to make in your project are as few as possible.</p>
<p>
<strong>Some of our deals were closed motivated by leadership&#39;s pressure to reduce the costs of CI or deliver features faster.</strong> Apple&#39;s ecosystem has solidified the idea that feedback cycles can take time and that every new year hardware can help cut time, although it&#39;s expensive for companies. But leadership doesn&#39;t always understand this. They see other ecosystems like the web being faster and cheaper, and they can&#39;t comprehend why. Many decide to <a href="https://shopify.engineering/migrating-our-largest-mobile-app-to-react-native#">move to React Native</a> motivated by that. In fact, Shopify did that, and while engineers might have mixed feelings about this, it&#39;s their approach to meet the demands of the market.</p>
<h2 id="dev-environments-and-app-quality" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dev environments and app quality<a href="#dev-environments-and-app-quality" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dev environments and app quality"></a></h2>
<p>
If we asked you what makes a healthy dev environment, you&#39;d have a hard time coming up with a concrete definition for it. However, if we asked you if you&#39;d use AI to enhance your dev environment, you&#39;d most likely be inclined to say yes, even if you don&#39;t know what &quot;better&quot; is, because everyone is doing it. Do you see our point?</p>
<p>
Take <a href="https://en.wikipedia.org/wiki/Code_coverage">test coverage</a>. A high test coverage doesn&#39;t necessarily mean the software does what it&#39;s supposed to do. However, there seems to be a consensus that that&#39;s the case, and we use the number to measure ourselves against ourselves and against others: what&#39;s your test coverage? How much higher did it get?</p>
<p>
With productivity—something we help improve in dev environments—there isn&#39;t a direct number you can put on it. There are endless frameworks that have attempted to quantify it, but since there are many factors that contribute to the speed of delivering software, it&#39;s rare to see a company valuing investment in this domain. For instance, we were chatting with a friend who recently joined an AI-first company. They&#39;ve given all developers access to <a href="https://www.cursor.com/">Cursor</a> and <a href="https://graphite.dev/">Graphite</a>, but even if that means developers write code faster, other elements in the software delivery chain are preventing any productivity boost. In fact, they can no longer do continuous delivery with confidence.</p>
<p>
As mentioned earlier, companies take productivity seriously if they have FOMO—for example, everyone is talking about Cursor and its productivity wins, and you want them too—or financial pressure, like paying a lot for costly CI macOS environments and wanting to cut costs. But a lot of it is just feelings. And depending on who you ask, different people experience productivity differently. For an iOS developer, waiting for a few minutes to see an app compiled is completely normal. A JavaScript developer would not deem it acceptable and would jump into figuring out ways to speed up compilation. So, in other words, the normalization of native app development being slow is our competitor.</p>
<p>
With app quality, a territory we are stepping into, it&#39;s a similar story. What&#39;s a healthy app? An app that&#39;s lightweight, fast, and stable... but it goes beyond that. It&#39;s an accessible app, visually and linguistically, that supports many devices, that makes good use of the device&#39;s battery. The list is endless, and without numbers around many of these things, many developers and companies might not see the value in investing in tools that help with that unless there are clear metrics or benchmarks. For example, if your app is above a certain size threshold, a percentage of users might not install it.</p>
<p>
Because of this, <strong>we are trying to understand how to measure some of these things</strong>, quantitatively and qualitatively, and provide teams and developers with those metrics so that they understand how it&#39;s impacting them. We are also encouraging developers to share their experiences. We said earlier that many times it&#39;s about feelings. We can talk forever about how challenging modular Xcode projects can be, but until you&#39;ve experienced it yourself, or someone that you trust has experienced it themselves, it remains as something that doesn&#39;t or won&#39;t happen to you.</p>
<h2 id="marketing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Marketing<a href="#marketing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Marketing"></a></h2>
<p>
There are many schools of marketing, and like many things in life, you can attempt to buy things with money—from paying people to talk about you to sponsoring conferences to place your logo. Done sporadically, this has a positive effect creating brand awareness, but doing too much of it can indeed have a negative effect. People can get tired of seeing you everywhere, and it feels forced. Developers don&#39;t typically respond well to that. Moreover, if you stop paying, and your logo fades, so does people&#39;s remembering of it. It lasts until you stop paying.</p>
<p>
We sometimes do a bit of that, but not all the time for the aforementioned reasons. We lean on word-of-mouth marketing. But how do you get people to talk about you without paying them? Or how do we build a solution that creates natural advocacy?</p>
<p>
This might sound trivial, and we&#39;re sure there are lengthy books written about it, but we get people to talk about us by being human and sharing our passion. We treat everyone as best as we can. They feel the joy we have about the app development space, and it has a contagious effect. They are happy with what they see to the point that they tell others about it, and this compounds. We share how our vision evolves and the things that we learned along the way, like this post that&#39;s a bit different from the type of content that you typically find on the Internet. We favor slow and deep content over attention-seeking content that just attempts to hack the algorithm of social networks. We don&#39;t feel like participating in those dynamics.</p>
<p>
We share a lot of our work as open source and support others in building their own tools and businesses on our foundation. We don&#39;t see the space as a competition ground but as a collaborative space where having many players is indeed positive. The more, the better. Our social accounts are just syndication of content that we publish in our blog and community forum.</p>
<p>
We show ourselves as we are. If we feel vulnerable, we talk about it. If we feel a space would benefit from some innovation, we share how we&#39;d shape it. There&#39;s really no playbook that you can follow top to bottom—it&#39;s more about people who share the same values and principles talking about what Tuist believes in and aspires to be.</p>
<p>
This has worked well for us, and we continue to see people and companies that come to us because they read about us, were told about us, or had Tuist on the list of tools that they were planning to use. We believe building a strong and long-lasting brand takes time, and while money can speed things up in certain moments, nothing can beat team, passion, and humanity.</p>
<h2 id="the-tuist-we-want-to-shape" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Tuist we want to shape<a href="#the-tuist-we-want-to-shape" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Tuist we want to shape"></a></h2>
<p>
If you wonder what we want Tuist to look like years from now, we want it to be the best toolchain to help you build great apps fast. It&#39;ll hold your hand from the moment you&#39;ve got an idea, offering you many templates to choose from, making the start more accessible, to doing releases, even on the go from an app. And we want this to span across other mobile platforms and technologies such as Android and potentially React Native. Shapes of this already exist in the web with platforms like <a href="https://vercel.com/">Vercel</a>. As development becomes more complex due to the surface of technologies, tools, frameworks, platforms, and products, building the muscle to help you stay focused, be productive, and ship the best apps to your users will get trickier and will require significant investment. While you could build those tools yourself, you can plug Tuist into your repo and <a href="https://appstoreconnect.apple.com">App Store Connect</a>, and we take care of the rest.</p>
<p>
Sounds ambitious, we know, but we believe we are on the right path. Deciding to start the business was the best decision we could have made for Tuist. We&#39;ve built a very talented team of people who are unique at their craft and a community that&#39;s also excited about evolving the experience of building and releasing apps with the world.</p>
<p>
We are figuring out the boring stuff and creating an innovative environment where everyone enjoys doing their best work, and we innovate without having to worry about new ideas having to be immediately monetizable.</p>
<p>
If you are going through something similar, want to evaluate Tuist for your project and support us, or you just want to chat, you can reach out to us at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a>. We&#39;d love to hear from you.</p>
<p>
<strong>This post was written by a human and its grammar reviewed with Claude 3.7 Sonnet.</strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Track and inspect your app bundle size with Tuist ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Use Tuist Bundle Analysis (bundle size insights) to minimize install and download size. ]]></summary>
      <link href="https://tuist.dev/blog/2025/05/15/bundle-size-analysis"/>
      <id>https://tuist.dev/blog/2025/05/15/bundle-size-analysis</id>
      <updated>Thu, 15 May 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
As your app evolves, its size inevitably increases. New features, additional assets, and expanding codebases all contribute to larger bundle sizes. Tuist Bundle Analysis gives you visibility into what&#39;s growing and why. Without proper visibility, it&#39;s easy to inadvertently bloat your app with:</p>
<ul>
  <li>
Duplicate assets across bundles  </li>
  <li>
Unused binary symbols  </li>
  <li>
Unoptimized resources  </li>
  <li>
Legacy code and dependencies  </li>
</ul>
<p>
A bloated app size doesn&#39;t just consume storage—it creates real business impact. Large apps face:</p>
<ul>
  <li>
<strong>Higher abandonment rates</strong>: When storage on a user&#39;s device is low, apps taking a lot of storage are the first ones to go.  </li>
  <li>
<strong>Lower conversion rates</strong>: Especially when downloading an app on cellular, a large download size can put away users.  </li>
  <li>
<strong>Exclusion of users</strong>: Large apps disproportionately affect users with storage limitations or bandwidth constraints.  </li>
</ul>
<p>
For developers in markets where mobile data is expensive or connections unreliable, an unnecessarily large app can effectively lock out potential users.</p>
<p>
Today, we&#39;re excited to announce a new Tuist feature that helps you keep your app&#39;s memory footprint small even as your app grows: <em>Tuist Bundle Analysis</em>.</p>
<p>
See the feature in action 👇 </p>
<iframe title="Tuist Bundle Analysis" width="560" height="315" src="https://videos.tuist.dev/videos/embed/49198B2y42DwaJGcp1HaJq" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="analyze-your-bundle" tabindex="-1" class="marketing__blog_post__body__content__heading">
Analyze your bundle<a href="#analyze-your-bundle" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Analyze your bundle"></a></h2>
<p>
To analyze your bundle, use the new <code class="inline">tuist inspect bundle</code> command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist inspect bundle App.ipa    </shiki-highlight>
  </div>
</div>
<p>
This command works with <code class="inline">.ipa</code>, <code class="inline">.xcarchive</code>, or <code class="inline">.app</code> files. After the bundle is analyzed, you&#39;ll receive a link to a comprehensive visual breakdown of your bundle:</p>
<p>
  <img src="/marketing/images/blog/2025/05/15/bundle-size-analysis/analyzed-bundle.png" alt="Analyzed bundle">
</p>
<p>
The interactive visualization, file breakdown, and module breakdown help you dive deep into your bundle, making it easier to identify possible areas of improvement.</p>
<h2 id="tracking-bundle-size-on-the-ci" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tracking bundle size on the CI<a href="#tracking-bundle-size-on-the-ci" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tracking bundle size on the CI"></a></h2>
<p>
How do you know when your bundle size is growing too large? By integrating bundle analysis into your CI pipeline, you can monitor how your app&#39;s footprint evolves with each build. You can set up a CI workflow to automate this process and analyze a bundle on each PR. We automatically collect Git and other metadata to make it easier to find specific bundles directly in the Tuist dashboard.</p>
<p>
Once integrated, you&#39;ll have access to historical size data visualized in clear, actionable charts:</p>
<p>
  <img src="/marketing/images/blog/2025/05/15/bundle-size-analysis/bundle-size-graph.png" alt="Bundle size graph">
</p>
<p>
This makes it easy to spot concerning trends or celebrate optimization wins—and hold your team accountable for maintaining a reasonable app size.</p>
<h2 id="open-sourced-foundations-–-rosalind" tabindex="-1" class="marketing__blog_post__body__content__heading">
Open-sourced foundations – Rosalind<a href="#open-sourced-foundations-–-rosalind" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Open-sourced foundations – Rosalind"></a></h2>
<p>
We are strong believers in open source at Tuist. That&#39;s why the core of the bundle analysis is done locally using our new library, <a href="https://github.com/tuist/Rosalind">Rosalind</a>. This library uses a standard schema with pre-defined categorization of the bundle contents. When you run <code class="inline">tuist inspect bundle</code> with a <code class="inline">--json</code> flag, you&#39;ll get the raw JSON output that comes directly from Rosalind. This is your gateway to build custom automations on top of what we offer.</p>
<p>
We can&#39;t wait to see what you come up with Rosalind – and we&#39;re committed to maintaing and updating the Rosalind schema to help you in your efforts.</p>
<h2 id="start-optimizing-your-bundles-today" tabindex="-1" class="marketing__blog_post__body__content__heading">
Start optimizing your bundles today<a href="#start-optimizing-your-bundles-today" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Start optimizing your bundles today"></a></h2>
<p>
There&#39;s a lot more that we have in store for the bundle analysis, such as expanding our <a href="https://github.com/marketplace/tuist">GitHub app</a> to warn you directly in the PR when the bundle size significantly increases, adding more insights into how you can optimize your bundle size, and giving you the tools to make individual teams accountable for their part of the bundle size.</p>
<p>
Bundle size isn&#39;t just about technical optimizations—it&#39;s about creating a better experience for your users and being a good platform citizen. With Tuist&#39;s bundle analysis, you now have the tools to ensure your app stays as lean as possible while still delivering all the features your users love.</p>
<p>
Ready to get started? Run <code class="inline">tuist inspect bundle</code> and discover opportunities to optimize your app size! </p>
<p>
For more details, <a href="https://docs.tuist.dev/en/guides/develop/bundle-size">head over to our documentation</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Vibe Xcoding your apps ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Explore how LLMs are changing the way we code and the exciting opportunities ahead as Apple brings 'vibe coding' to the Xcode ecosystem for Swift developers. ]]></summary>
      <link href="https://tuist.dev/blog/2025/05/13/vibe-xcoding"/>
      <id>https://tuist.dev/blog/2025/05/13/vibe-xcoding</id>
      <updated>Tue, 13 May 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<strong>This article is for iOS, macOS, and Swift developers interested in the future of AI-assisted coding, especially those working with Xcode who want to understand how LLMs and &quot;vibe coding&quot; could transform their development workflow. It&#39;s also relevant for technical leaders evaluating how these technologies might impact Apple&#39;s developer ecosystem.</strong></p>
<p>
LLMs are here to stay.
Many developers are exploring how they can have a positive impact on how we code,
and that exploration gave birth to a concept you might have heard of: <a href="https://en.wikipedia.org/wiki/Vibe_coding">vibe coding</a>.
Unlike the approach to coding that we know and have used for endless years,
vibe coding proposes that you partner with an LLM letting it write and iterate on the code with context from you and the codebase you are interacting with.
Whether the future of vibe coding will have the shape that we are seeing today, and whether it&#39;ll be used for coding entire projects,
is yet to be seen since we are just at the beginning of loads of creativity and mental energy going into the space,
however, what&#39;s becoming more and more clear is that the idea of having an AI-powered copilot is here to stay,
and for certain tasks, it can indeed save you a lot of time.
Editors like <a href="https://code.visualstudio.com">VSCode</a>, <a href="https://www.cursor.com">Cursor</a>, <a href="https://zed.dev">Zed</a>, or <a href="https://windsurf.com/editor">Windsurf</a>, have built on this idea,
and are continuously exploring new UI and UX patterns that can unlock new ways of approaching code.</p>
<p>
If you are developing apps using Xcode,
you might understandably wonder, where is vibe coding in Xcode? When will it come?
With WWDC around the corner,
we&#39;d like to walk you through some work that&#39;s being done by the community to bridge that gap,
and take the opportunity to talk about the exciting opportunities ahead as Apple prepares to enhance the Xcode experience with AI capabilities that could surpass what we see in other ecosystems.</p>
<h2 id="a-vibe-coding-copilot" tabindex="-1" class="marketing__blog_post__body__content__heading">
A vibe-coding copilot<a href="#a-vibe-coding-copilot" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A vibe-coding copilot"></a></h2>
<p>
Vibe coding requires a chat interface that&#39;s plugged into your coding interface to write code for you, and also to gather context from the editor.
There are editors like VSCode whose extensibility allows a tight integration, and there are others like Xcode, which were not designed with a high degree of extensibility in mind,
yet it hasn&#39;t prevented developers to push the boundaries of what&#39;s possible and bring the same experience to Xcode.
Two of the most popular options are <a href="https://www.alexcodes.app/">Alex</a>, which presents itself as an Xcode AI Coding assistant,
and <a href="https://github.com/github/CopilotForXcode">CopilotForXcode</a>, an open source project developed and maintained by GitHub to integrate Xcode with their copilot offering.</p>
<p>
It&#39;s quite impressive to see what they are capable of doing despite the limitations of the IDE, but they managed to workaround those using the system accessibility APIs.
From the two, Alex is the most actively maintained, and the experience that they provide is quite close to what you&#39;d get from other vibe coding editors.</p>
<p>
This opens up exciting possibilities for how Apple might approach AI integration - whether by embedding a thoughtfully designed chat interface into Xcode&#39;s UI, or by expanding the extensibility of the existing interface to allow applications like Alex to seamlessly integrate and access runtime information, which would enhance the assisted experience quite significantly. Given Apple&#39;s history of refining technologies before bringing them to market, we&#39;re eager to see their unique perspective on this space. And this brings us to the importance of having up-to-date and relevant context while interacting with the LLM.</p>
<h2 id="context" tabindex="-1" class="marketing__blog_post__body__content__heading">
Context<a href="#context" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Context"></a></h2>
<p>
For LLMs to do a great job at the tasks you ask them to do, they need a lot of context.
Some of that context can be provided by you via the prompts, for example if you want to vibe-code a UI, you can describe what the UI is for, what kind of data you plan to present, and even ask to populate the UI with some mock data for the purposes of prototyping.
However, that&#39;s often not enough.
The editor needs additional context to output code that can be integrated,
and in the case of an Xcode codebase,
compiled by the Swift compiler leading to an app that runs.
For example, the version of Swift that your project is using,
the structure of the Xcode project where it might need to add some files to the file group and to a sources build phase,
or the schemes that are available to build a runnable application.</p>
<p>
This notion of LLMs talking to the outside world
is a need that <a href="https://www.anthropic.com">Anthropic</a> realized,
and that led to the definition of a protocol, <a href="https://modelcontextprotocol.io/introduction">Model Context Protocol (MCP)</a>,
which many called the <a href="https://en.wikipedia.org/wiki/USB-C">USB-C</a> of LLMs.
MCP aims to be a standard protocol for how LLMs can interact with the outside world,
either to gather additional context, or even run tasks in your system,
like building and running an app in the simulator.
While MCP got popular among code editors,
it&#39;s true that since it&#39;s coming from Anthropic,
there are some companies like OpenAI that are hesitant to adopt it,
and others that are proposing new protocols,
leading to a bit of an unfortunate situation for the ecosystem where there are multiple protocols for achieving the same thing.</p>
<p>
The lack of MCP support in Alex (CopilotForXcode just <a href="https://x.com/jialuogan/status/1922205712039461028">announced support for it</a>) hasn&#39;t prevented the community from going ahead and building MCP servers for Xcode app developers.
From all of them, one that&#39;s getting a lot of traction and it&#39;s quite actively developed is <a href="https://github.com/cameroncooke">Cameron Cooke</a>&#39;s <a href="https://github.com/cameroncooke/XcodeBuildMCP">XcodeBuildMCP</a>,
which you can plug into <a href="https://claude.ai/download">Claude desktop</a> or other code editors like Zed or Cursor.
With it you can do things like building and running an app,
or managing your simulators.
Some of this functionality is already built into Alex, 
but once they support MCP servers,
you can think of MCP servers like XcodebeBuildMCP as &quot;extensions&quot; of vibe-code editors.</p>
<p>
So we have solutions that bring the coding experience closer to Xcode, we have MCP servers that can bridge LLMs with the Xcode and app development world,
what&#39;s missing you might guess... Well quite a lot indeed, and some changes in foundational pieces in the Apple ecosystem, without which the vibe coding experience will lag behind.</p>
<h2 id="built-in-extensibility" tabindex="-1" class="marketing__blog_post__body__content__heading">
Built-in extensibility<a href="#built-in-extensibility" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Built-in extensibility"></a></h2>
<p>
There&#39;s a limit to how much Alex or CopilotForXcode can do and read through the accessibility API.
On one side, this is excellent for Apple because it puts them in a unique position to build a more tightly integrated experience that could redefine developer workflows,
and this is something that we know well at Tuist (wink, wink).
Apple has consistently demonstrated their ability to take emerging technologies and elevate them through thoughtful integration with their platforms. While AI development may not have been their primary focus historically, Apple&#39;s track record of transforming industries when they do decide to fully enter a space is impressive.
Imagine if instead they started layering Xcode, opening the bottom-most layers, and giving developers the tools to extend it.
Sounds familiar? That&#39;s what Microsoft did with VSCode, and what has given the explosion to editors like Windsurf, Cursor, or <a href="https://github.com/voideditor/void">Void</a>, and we&#39;ll most likely see more in the years to come.
Xcode&#39;s extensibility has historically been limited by design,
but there are encouraging signs that Apple recognizes the tremendous value in opening up their developer tools. With the growing importance of AI in development workflows, this year could mark a turning point where Apple embraces a more open approach to their tooling, unlocking a world of new coding possibilities for app developers.</p>
<p>
Thanks to that, extensions like Alex or CopilotForXcode wouldn&#39;t have to rely on a high-level API like the accessibility,
they could hook into the internals of Xcode and even use their internal APIs for interacting with Xcode projects,
for example to add a source file to a target,
or to know which files are compiled as part of a target.</p>
<h2 id="shorter-feedback-cycles" tabindex="-1" class="marketing__blog_post__body__content__heading">
Shorter feedback cycles<a href="#shorter-feedback-cycles" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Shorter feedback cycles"></a></h2>
<p>
When doing vibe coding, there&#39;s an agent mode, where you give the interface a set of requirements,
and they go ahead and do the work for you.
This is often referred to as &quot;agentic&quot; AI.
This mode requires having a way for the AI to verify that the changes are valid,
similar to how you do when you hit compile or run the tests, to make sure the code compiles and does what it&#39;s supposed to do.
If those &quot;checks&quot; run fast,
the agent can iterate fast based on your input,
however,
if they are slow,
or even worse,
they are unreliable,
it can completely spoil the &quot;vibe&quot; in the coding.</p>
<p>
Sounds familiar? This is the scenario that developers face every day in their day-to-day development,
and that motivated the creation of Tuist in the first place:
unreliable builds caused by implicit configuration, frequent deletion of derived data in the aim of making a compilation work,
one-line changes that trigger long compilations...
Many of us might have normalized all of that as inherent to building apps with Xcode.
This has led some organizations to explore alternative approaches using JavaScript runtimes. 
Attempting to vibe-code gives us a fresh perspective on developer experience and highlights opportunities for enhancing performance in ways that Apple is uniquely positioned to address.</p>
<p>
While the current &quot;vibe&quot; coding experience has room for growth, Apple is already laying the groundwork for significant improvements.
Last year they introduced <a href="https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies">explicit modules</a> - a forward-thinking move that shows their awareness of what&#39;s needed for better tooling integration.
They&#39;re also working on a sophisticated <a href="https://github.com/swiftlang/swift-build/tree/main/Sources/SWBCAS">content addressable store</a>, 
which demonstrates Apple&#39;s commitment to building the foundation for next-generation development experiences.
So while other runtimes like the web platform,
where you can throw React or web components and see them being reloaded in seconds,
we are insanely far from enabling the same experience in Xcode.
We need to finally move on from all that implicitness that brought teams the convenience to modularize,
and introduce more explicitness and dynamism into the toolchain such that you can iterate in a small part of your apps.</p>
<p>
Who knows... perhaps we move in the direction of <a href="https://github.com/krzysztofzablocki/Inject">doing code-injection</a> escaping the compiler all together,
but once again, this is another area where language convenience, like being able to reference a symbol without the full symbol identifier, might come at the cost of once more, not being able to enable certain developer experiences.</p>
<h2 id="runtime-context" tabindex="-1" class="marketing__blog_post__body__content__heading">
Runtime context<a href="#runtime-context" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Runtime context"></a></h2>
<p>
Another piece of information that will be useful as well will be runtime context.
A few weeks ago the developers behind the <a href="https://elixir-lang.org">Elixir programming language</a> and the <a href="https://www.phoenixframework.org">Phoenix web framework</a> introduced <a href="https://tidewave.ai">Tidewave</a>,
which they presented as a technology to expose runtime context from web apps to MCP-compatible code editors.</p>
<p>
When your software is running, 
there&#39;s a lot of runtime context in it that might be useful to further enhance the vibe coding experience.
For example, imagine being able to debug your API client by sending requests through Claude and asking it to verify the responses and iterate on the code based on what they see in the responses.
These are just some examples, but you get the idea.
The more context, the better,
and runtime context can be quite useful.</p>
<p>
In that sense,
using runtime solutions that model problem spaces very declaratively can play a key role in enhancing your vibe coding experiences.
And there&#39;s no better example than Point Free&#39;s architectural approach.
Your application state lives in a store, and the mutations that are possible are known at compilation-time, so you could trigger those mutations,
not by interacting with UI, but by chatting with an LLM. Wouldn&#39;t that be cool?
The agent could navigate the app, and who knows,
even reach user scenarios that you didn&#39;t think of and write some tests for you.
The possibilities are endless.</p>
<p>
In that regard, we wonder if Apple will introduce an official framework that can be used by other frameworks and libraries
to have a unified way to share context with the outside world.
Ideally, they&#39;d expose an MCP server,
but we all know Apple likes to sometimes go the proprietary path and come up with proprietary solutions.
This is a direction that sooner or later will be more deeply explored by the ecosystem.</p>
<h2 id="better-documentation-and-examples" tabindex="-1" class="marketing__blog_post__body__content__heading">
Better documentation and examples<a href="#better-documentation-and-examples" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Better documentation and examples"></a></h2>
<p>
LLMs are trained with existing code examples and documentation.
Therefore, the more and the better they are, the better the work that LLMs produce will be.
Unlike the web, where there are plenty of open source projects and libraries to learn from,
the number of open source projects and apps out there to learn from is quite limited.
One could argue that Apple could use their own projects,
but are they in a state where they can be used to train models?
Only Apple and their engineers know,
but that might not be the case.
So if there are not that many references out there,
this will unfortunately make LLMs not as good at writing Swift as they might be in other languages.
And the same goes for the docs.
The documentation of the frameworks and the programming language needs to be top-notch.
It needs to cover in detail what the APIs are for,
include multiple examples of how they can be used and the output that they&#39;d produce in those cases,
and also caveats that someone should be aware of.</p>
<p>
It almost feels as if all your past investment into great docs and examples is finally being put into practice.
The good thing is that if the LLMs are not doing a great job, you can blame someone else,
but the reality is that a lot has to do with all that data it&#39;s been trained with.
The push for vibe coding can finally be a wake up call for Apple to fill many gaps in their documentation,
ensure they provide as many examples as they can,
and expose an <a href="https://llmstxt.org">llms.txt</a> endpoint that LLMs can use to improve their models.</p>
<h2 id="explicitness,-explicitness,-explicitness" tabindex="-1" class="marketing__blog_post__body__content__heading">
Explicitness, explicitness, explicitness<a href="#explicitness,-explicitness,-explicitness" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Explicitness, explicitness, explicitness"></a></h2>
<p>
The more explicit the context is and the dependencies between different pieces of context,
the more likely LLMs will do a better job at their tasks.
Take for instance <a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0439-trailing-comma-lists.md">this Swift evolution</a> proposal,
which introduced support for trailing commas in comma-separated lists.
As a language addition,
it&#39;s a great convenient improvement.
However, it&#39;s only supported from the Swift version 6.1.
In other words,
to know whether that feature can be used,
the LLM needs to know which Swift version a target in your Xcode project is compiled with,
and if this information is dynamically resolved at build time based on the build configuration and a setting in an .xcconfig file,
the chances that the LLM uses that information to use the right language features is very unlikely,
so you&#39;ll force the agent into a trial-and-error approach to coding for you,
which is slow and frustrating.</p>
<p>
Therefore, I believe in this new world we are entering,
it&#39;s crucial that we embrace explicitness, and that we make all that information accessible to LLMs,
so the more open, the better.
Otherwise we&#39;ll fall way behind in what &quot;vibe coding&quot; means in the web vs Swift app development ecosystem.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
It&#39;s early to know what vibe coding will look like in years from now,
but it&#39;s clear that it&#39;s here to stay,
and with so much creative energy and capital going to the space the concept is likely to evolve and challenge our approach to coding.
Apple&#39;s thoughtfully designed solutions and mental models have served developers well for many years,
and now they have an exciting opportunity to evolve these approaches for the LLM era, where high-quality, explicit, and accessible context becomes increasingly valuable.
We can see vibe coding as an inspiring catalyst for Apple&#39;s next leap in developer tools,
and given their history of transforming industries through careful innovation and integration,
we&#39;re optimistic about how they&#39;ll enhance their already robust software ecosystem,
potentially pioneering new approaches that align with their commitment to quality and providing developers with exceptional tools to build remarkable apps.</p>
<p>
If this is a space that piques your interest, we recommend following the work that <a href="https://www.async-let.com">Cameron</a>, <a href="https://academy.rudrank.com">Rudrank</a>, and <a href="https://www.dimillian.app">Thomas</a> are doing bridging the gap between Xcode and AI.</p>
<p>
<strong><em>This post was written by humans with grammar and style reviewed by Claude 3.7 Sonnet.</em></strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Meet the new Tuist dashboard ]]></title>
      
      
      <author>
        <name><![CDATA[  Asmit Malakannawar  ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ After months of work, we're excited to release a redesign of the Tuist dashboard, our new foundation to deliver the best developer experience possible. ]]></summary>
      <link href="https://tuist.dev/blog/2025/04/17/meet-new-tuist"/>
      <id>https://tuist.dev/blog/2025/04/17/meet-new-tuist</id>
      <updated>Thu, 17 Apr 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
  <img src="/marketing/images/blog/2025/04/17/meet-new-tuist/og.png" alt="Meet the new Tuist illustration">
</p>
<p>
When you&#39;re building software, the user interface is usually the first thing people notice. Every app or tool is built from countless hours of hard work by developers, and it&#39;s the right developer tools that make the app development process smooth and efficient. A good UI isn’t just about looking nice—it’s about creating a smooth, efficient experience that helps users get things done quickly.</p>
<p>
And if you want to see the new dashboard in action, you can take a look at the open <a href="https://tuist.dev/tuist/tuist">Tuist dashboard</a> (yes, we use Tuist with Tuist).</p>
<h3 id="why-redesign" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why redesign<a href="#why-redesign" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why redesign"></a></h3>
<p>
The value Tuist brings is really important to us. While our primary platform is the CLI, we also wanted to make sure the web interface was easy to use. Although our CLI saw a <a href="https://swifttoolkit.dev/posts/noora-package">major upgrade</a>, the web interface still had room for improvement. Other developer tools like <a href="https://vercel.com/home">Vercel</a>, <a href="https://supabase.com/">Supabase</a>, and <a href="https://buildkite.com/">Buildkite</a> have set a high standard, and we wanted to bring that same level of quality to the app development ecosystem. Through our exploration, we identified several challenges, including:</p>
<ul>
  <li>
Enhancing the overall navigation experience    </li>
  <li>
Adapting to the product changes    </li>
  <li>
Highlighting only the most important information   </li>
</ul>
<h3 id="the-first-steps" tabindex="-1" class="marketing__blog_post__body__content__heading">
The first steps<a href="#the-first-steps" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The first steps"></a></h3>
<p>
Tuist&#39;s previous dashboard was built using the <a href="https://www.untitledui.com/">Untitled UI</a> design system. While it&#39;s a great design system overall, as projects grow, you need new components that fit within the existing framework. This can make it tricky to work with components on the design side. When I joined Tuist, my goal was to create a more accessible, scalable, and open-source design system. We named it Noora. The Noora design system will be the foundation for shaping not just our dashboard, but also our websites, marketing materials, apps, and more. To keep the community in the loop, I started a <a href="https://community.tuist.dev/t/redesign-initiative-at-tuist/138/5">redesign initiative</a> on our community platform, where I updated the progress of the design system every two weeks.</p>
<h3 id="meet-the-new-tuist-dashboard" tabindex="-1" class="marketing__blog_post__body__content__heading">
Meet the new Tuist dashboard<a href="#meet-the-new-tuist-dashboard" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Meet the new Tuist dashboard"></a></h3>
<p>
  <img src="/marketing/images/blog/2025/04/17/meet-new-tuist/dashboard.png" alt="Screenshot of the Tuist dashboard">
</p>
<p>
This redesign wasn’t just about updating the UI; our goal was to make the developer experience more intuitive. We analyzed platforms like <a href="https://supabase.com/">Supabase</a>, <a href="https://appwrite.io/">Appwrite</a>, <a href="https://www.gitpod.io/">Gitpod</a>, <a href="https://www.appsignal.com/">AppSignal</a>, <a href="https://vercel.com/home">Vercel</a>, and <a href="https://buildkite.com/">Buildkite</a> to understand how to structure data and prioritize what matters most to developers. Our focus was on reducing noise and presenting only the essential information.</p>
<p>
After multiple iterations, experimenting with multiple design directions, we finally landed on a layout that felt easy to navigate and where the content was well-structured.</p>
<h3 id="what’s-new" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s new<a href="#what’s-new" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s new"></a></h3>
<p>
Our updated interface design is now easier to use, more intuitive, and visually appealing—because we believe great design is not just about aesthetics, but about how well it serves you.</p>
<p>
<strong>New UI</strong></p>
<p>
While all core functionalities remain, this new version of the dashboard introduces some exciting new capabilities—like creating organizations and projects, and inviting members directly from the dashboard. Previously, these features were available only via the CLI, but we&#39;re moving toward feature parity between the dashboard and CLI wherever it makes sense. The updated UI provides a cleaner, more modern workspace, helping you focus on what really matters: speeding up app development.</p>
<p>
<strong>New onboarding flow</strong></p>
<p>
The updated onboarding flow allows you to create projects right after signing up on the web. We’ve also introduced a new accounts section where you can view your latest projects, billing details, settings, and more.  <br>
  <img src="/marketing/images/blog/2025/04/17/meet-new-tuist/onboarding.png" alt="Screenshot of the new onboarding flow">
</p>
<p>
<strong>Updated color palette</strong></p>
<p>
We’ve chosen the OKLCH color space for our palette due to its superior accessibility, flexibility in color adjustments, and extensive color range. Unlike traditional color spaces, OKLCH aligns more closely with human perception, making it ideal for creating a visually balanced and accessible interface. For more in-depth information, check out this <a href="https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl">blog post</a>.  <br>
  <img src="/marketing/images/blog/2025/04/17/meet-new-tuist/new-palette.png" alt="Screenshot of the new Tuist palette">
</p>
<p>
<strong>Updated components</strong></p>
<p>
Buttons, inputs, tables, and other UI elements have been redesigned for a sleek, consistent look, ensuring the platform not only performs well but also looks fantastic. We incorporated a skeuomorphic style with a modern twist to bring depth to our dashboard. It’s like the good old days, but better.</p>
<p>
  <img src="/marketing/images/blog/2025/04/17/meet-new-tuist/components.png" alt="Screenshot of the updated components">
</p>
<p>
<strong>Light and dark modes</strong></p>
<p>
Previously, our platform only offered dark mode, but now we’ve added light mode as well. You can easily switch between light and dark modes for a more comfortable experience, anytime you like.</p>
<p>
  <img src="/marketing/images/blog/2025/04/17/meet-new-tuist/light-dark-mode.png" alt="Screenshot of the light/dark mode">
</p>
<h3 id="what’s-next:" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next:<a href="#what’s-next:" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next:"></a></h3>
<p>
We’re just getting started—and here’s a glimpse of what’s coming:</p>
<ul>
  <li>
    <p>
<strong>Bring full feature parity between the CLI and dashboard:</strong>
We’re working toward a seamless experience where developers can choose their preferred interface without sacrificing functionality.    </p>
  </li>
  <li>
    <p>
<strong>Expand our design across marketing surfaces and further invest in Noora for the CLI:</strong>
We want our visual identity to be consistent across every touchpoint, and we’re doubling down on Noora to bring clarity and structure to the CLI experience.    </p>
  </li>
  <li>
    <p>
<strong>Make the design system open:</strong>
We plan to share the Noora design system publicly—including the Figma file and source assets—to support and inspire other teams in the community.    </p>
  </li>
</ul>
<p>
Read more about our <a href="/blog/2025/04/10/one-stop-shop">open source plans in our latest blog post</a> — and we can&#39;t wait to see how developers use all this to create better, faster experiences for app makers everywhere.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Automate your Swift projects ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We compare various automation options for Swift projects including Fastlane, Sake, swift-sh, bash, and other scripting languages. Our guide presents practical examples and trade-offs to help developers select the most appropriate solution for their specific needs, suitable for both newcomers and those evolving existing automation setups. ]]></summary>
      <link href="https://tuist.dev/blog/2025/04/15/automation-in-swift-projects"/>
      <id>https://tuist.dev/blog/2025/04/15/automation-in-swift-projects</id>
      <updated>Tue, 15 Apr 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<strong>Audience: Developers who are new to the ecosystem and have recognized the need for automation, or developers with existing codebases that include automation who are looking to evolve their setups. All examples mentioned in this post are included in <a href="https://github.com/tuist/automation-in-swift-projects-reference">this repository</a> for your reference.</strong></p>
<p>
If you are an app developer, you most likely want to automate certain tasks in your projects, such as publishing your app to the <a href="https://www.apple.com/app-store/">App Store</a> or running tests from the terminal. <a href="https://apple.com">Apple</a> provides the foundational building blocks for these automations, which are included in the OS and in Xcode&#39;s toolchain. However, in many cases, these tools are too low-level, requiring a layer of convenience through defaults or the construction of more advanced workflows that connect these low-level components—potentially parallelizing some of the steps for improved efficiency.</p>
<p>
In this comprehensive post, we&#39;ll explore a non-exhaustive list of relevant options that you might consider adopting for your projects. Each approach has its unique strengths and trade-offs, which we&#39;ll examine to help you make an informed decision based on your specific needs and constraints.</p>
<h2 id="fastlane:-the-established-solution" tabindex="-1" class="marketing__blog_post__body__content__heading">
Fastlane: The established solution<a href="#fastlane:-the-established-solution" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Fastlane: The established solution"></a></h2>
<p>
<a href="https://fastlane.tools/">Fastlane</a> is a well-established solution in the automation space. If you&#39;re new to app development, this might sound unfamiliar, but virtually everyone who has been developing apps for a while knows about Fastlane and its capabilities.</p>
<p>
Fastlane is a <a href="https://www.ruby-lang.org/en/">Ruby</a>-based solution that provides a Domain Specific Language (DSL) for defining workflows, along with a set of low-level tools that fill certain gaps in the underlying Apple tools. It adds convenience through more sensible defaults and streamlined processes. Its greatest strength lies in its vast <a href="https://docs.fastlane.tools/plugins/available-plugins/">ecosystem of plugins</a>, most of which were developed and are maintained by the community. These plugins are distributed as Ruby dependencies using Ruby&#39;s dependency management system, <a href="https://bundler.io">Bundler</a>, and can be added with a single command or line of code.</p>
<p>
One of the perceived downsides of Fastlane is that you might need to familiarize yourself with Ruby if you haven&#39;t written it before. The inconsistency between the language used by Fastlane (Ruby) and the one used to develop your app (Swift) might feel uncomfortable, and that explains the emergence of other solutions that aim to take on the role of Fastlane. However, by choosing an alternative, you&#39;d be trading away Fastlane&#39;s extensive ecosystem—something that&#39;s not easily replicated by newer tools.</p>
<p>
To use Fastlane effectively, you&#39;ll need to add Ruby and Fastlane as dependencies of your project, and then create a <code class="inline">Fastfile</code>, which is the place where you&#39;ll define your project&#39;s automation. With <a href="https://mise.jdx.dev">Mise</a>, you can do this easily in your <code class="inline">mise.toml</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[tools]
ruby = &quot;{{ get_env(name=&#39;RUBY_VERSION&#39;, default=&#39;3.4.3&#39;) }}&quot;
&quot;gem:fastlane&quot; =  &quot;2.227.1&quot;    </shiki-highlight>
  </div>
</div>
<p>
With a simple <code class="inline">mise install</code> command, you&#39;ll get the environment provisioned with the necessary dependencies. You can then create a <code class="inline">fastlane/Fastfile</code> where you&#39;ll declare what Fastlane calls &quot;lanes.&quot; Think of lanes as workflows or tasks that encapsulate a series of related operations. For example, the following lane builds a project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
ruby    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="ruby">
lane :build do
  gym(
    project: &quot;Automation/Automation.xcodeproj&quot;,
    skip_package_ipa: true,
    skip_archive: true,
    skip_codesigning: true
  )
end    </shiki-highlight>
  </div>
</div>
<p>
This example is quite simple, but in your actual tasks, you&#39;ll most likely add more steps that will run sequentially before or after the project builds. For instance, you might include steps to provision your environment to enable proper app signing, run tests, or perform post-build validation.</p>
<h2 id="sake:-swift-based-automation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Sake: Swift-based automation<a href="#sake:-swift-based-automation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Sake: Swift-based automation"></a></h2>
<p>
If you prefer to align the automation language with your application programming language (i.e., <a href="https://www.swift.org">Swift</a>), another interesting solution is <a href="https://sakeswift.org/">Sake</a>, which draws inspiration for its name and approach from the well-known <a href="https://www.gnu.org/software/make/">Make</a> build automation tool. A Sake setup is a <a href="https://www.swift.org/documentation/package-manager/">Swift Package</a> with a Command Line Interface (CLI) and API that provides a layer of convenience around lower-level tools.</p>
<p>
Modeling your automation as a Swift Package allows Sake to leverage SwiftPM as both a build tool and dependency manager. This is particularly useful if you want to reuse Swift Packages implemented by the community, such as a <a href="https://github.com/AvdLee/appstoreconnect-swift-sdk">Swift SDK</a> to interact with the <a href="https://developer.apple.com/documentation/appstoreconnectapi">App Store Connect API</a>.</p>
<p>
Continuing with our example of building an app, we can implement the same logic as in the Fastlane example in a Swift <code class="inline">Sakefile</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import Foundation
import Sake
import Command
import Path

@main
@CommandGroup
struct Commands: SakeApp {
    public static var build: Sake.Command {
        Command(
            run: { _ in
                let sakefilePath = try AbsolutePath(validating: #file, relativeTo: try AbsolutePath(validating: FileManager.default.currentDirectoryPath))
                let rootDirectory = sakefilePath.parentDirectory.parentDirectory
                
                try await CommandRunner().run(arguments: [
                    &quot;/usr/bin/xcrun&quot;, &quot;xcodebuild&quot;,
                    &quot;-project&quot;, rootDirectory.appending(components: [&quot;Automation&quot;, &quot;Automation.xcodeproj&quot;]).pathString,
                    &quot;-scheme&quot;, &quot;Automation&quot;,
                    &quot;-destination&quot;, &quot;generic/platform=iOS&quot;,
                    &quot;CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=&#39;&#39;&quot;
                ]).pipedStream().awaitCompletion()
                
            }
        )
    }
}    </shiki-highlight>
  </div>
</div>
<p>
The first thing you&#39;ll notice is that this is written in Swift, a language with which you&#39;re likely already familiar if you&#39;re developing iOS apps. Conceptually, the idea is similar to Fastlane, where you have tasks that are executed in sequence. In Sake, these tasks are declared as static variables in a <code class="inline">@main</code> struct.</p>
<p>
Another aspect you&#39;ll notice if you run Sake for the first time is that <strong>it will take some time</strong> to fetch the dependencies and warm the build cache. If you&#39;re accustomed to scripts in bash or interpreted languages, this might initially feel like a degradation in developer experience. However, subsequent runs should be much faster once the dependencies are cached. Think of Sake as trading Fastlane&#39;s instant launch time for the ability to write your automation in Swift, a language you&#39;re already using for your app development.</p>
<h2 id="swift-sh:-single-file-swift-scripts" tabindex="-1" class="marketing__blog_post__body__content__heading">
swift-sh: Single-file Swift scripts<a href="#swift-sh:-single-file-swift-scripts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to swift-sh: Single-file Swift scripts"></a></h2>
<p>
In a similar vein as Sake, there&#39;s another tool that allows you to write your scripts in Swift: <a href="https://github.com/mxcl/swift-sh">swift-sh</a>. Like Sake, swift-sh undergoes a dependency-fetching and building process, so cold runs will take time to complete. However, swift-sh completely abstracts away packages to the point that your workflow is literally one portable file with annotations at the top for declaring dependencies.</p>
<p>
We can transform the previous script into a one-file swift-sh script:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
#!/usr/bin/swift sh

import Command  // tuist/command ~&gt; 0.13.0
import Foundation
import Path  // tuist/path ~&gt; 0.3.8

if CommandLine.arguments.count == 2 {
    let projectPath = try AbsolutePath(
        validating: CommandLine.arguments[1],
        relativeTo: try AbsolutePath(validating: FileManager.default.currentDirectoryPath))

    try await CommandRunner().run(arguments: [
        &quot;/usr/bin/xcrun&quot;, &quot;xcodebuild&quot;,
        &quot;-project&quot;,
        projectPath.pathString,
        &quot;-scheme&quot;, &quot;Automation&quot;,
        &quot;-destination&quot;, &quot;generic/platform=iOS&quot;,
        &quot;CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=&#39;&#39;&quot;,
    ]).pipedStream().awaitCompletion()
    
} else {
    print(&quot;Usage: ./build.swift path/to/project.xcodeproj&quot;)
    exit(1)
}    </shiki-highlight>
  </div>
</div>
<p>
Swift-sh achieves script portability by leveraging annotations placed next to imports. These annotations are then converted to a SwiftPM package in a global cache directory for you behind the scenes. One caveat of this approach is that since the files are copied into the cache directory, we can&#39;t obtain the root of the project&#39;s directory relative to the path of the script.</p>
<p>
One option could be to make paths relative to the working directory, but that would couple the execution of the script to the root directory, which is not ideal for flexibility. In the above script, we decided to pass the path as the first argument when invoking the script: <code class="inline">./build.swift Automation/Automation.xcodeproj</code>. This approach makes the script more versatile and usable from different locations.</p>
<p>
We haven&#39;t discussed argument parsing yet, but in both Swift approaches—Sake and swift-sh—you can make use of Apple&#39;s excellent <a href="https://github.com/apple/swift-argument-parser">swift-argument-parser</a> package to declare and parse command-line arguments. You can use <a href="https://sakeswift.org/advanced-argument-parsing.html">this example</a> as a reference for implementing more sophisticated argument handling.</p>
<h2 id="bash:-unbeatable-portability" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bash: Unbeatable portability<a href="#bash:-unbeatable-portability" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bash: Unbeatable portability"></a></h2>
<p>
Perhaps the most obvious approach, but still worth mentioning, is writing your scripts in bash. Bash scripts offer unbeatable portability and launch time advantages. They run instantly on virtually any Unix-like system without requiring any additional runtime or dependencies.</p>
<p>
The primary challenge with bash scripts is, well... writing bash. It&#39;s not the most enjoyable scripting language to use for complex tasks. The syntax might feel too verbose, and pieces of logic can be difficult to encapsulate and reuse effectively. However, Large Language Models (LLMs) are changing this landscape dramatically.</p>
<p>
LLMs are becoming increasingly capable of writing code, and scripting code is something they can do very well, including bash. This approach is becoming so popular that developers have coined a term for it: <a href="https://en.wikipedia.org/wiki/Vibe_coding">&quot;vibe coding.&quot;</a> You can effectively &quot;vibe code&quot; your bash scripts, and it&#39;s easier than you might think. These scripts generally require low maintenance, but even when maintenance is needed—for example, to add functionality or optimize performance—you can also leverage LLM solutions to assist with these tasks.</p>
<p>
Here&#39;s a simple bash script example that performs the same build operation:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env bash

set -eo pipefail

ROOT_DIR=&quot;$(cd &quot;$(dirname &quot;${BASH_SOURCE[0]}&quot;)&quot; &amp;&amp; pwd)&quot;

/usr/bin/xcrun xcodebuild \
  -project $ROOT_DIR/Automation/Automation.xcodeproj \
  -scheme &quot;Automation&quot; \
  -destination &quot;generic/platform=iOS&quot; \
  CODE_SIGNING_ALLOWED=NO \
  CODE_SIGNING_REQUIRED=NO \
  CODE_SIGN_IDENTITY=&quot;&quot;    </shiki-highlight>
  </div>
</div>
<p>
Note in the example above that, similar to Sake, we can easily get the directory containing the script and use it to construct the path to the Xcode project. If you compare this approach to the Swift and Ruby versions, it&#39;s slightly more verbose but not significantly so. Things might become more complex as you add control flows and error handling, but you&#39;d be surprised at how manageable these scripts can remain, especially with the help of modern tools and LLMs.</p>
<p>
If you&#39;d like to define a user-friendly interface for your bash scripts—for example, to pass flags and arguments—doing so in pure bash can result in a lot of boilerplate code. Fortunately, <a href="https://github.com/jdx/usage">usage</a>, created by the same developer as Mise, allows you to define that interface using comments in the script:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env -S usage bash
#USAGE flag &quot;-c --clean&quot; help=&quot;Clean the project before building&quot;

if [ &quot;$usage_clean&quot; = &quot;true&quot; ]; then
  # Call xcodebuild passing the &#39;clean&#39; argument
fi    </shiki-highlight>
  </div>
</div>
<p>
Note the change in the shebang line, which now runs <code class="inline">usage bash</code> instead of just <code class="inline">bash</code>. The &quot;usage&quot; tool will parse the <code class="inline">#USAGE</code> comments to construct the command-line interface for you, parse the provided arguments, and expose them as environment variables that follow the naming convention <code class="inline">usage_$name</code>. This approach significantly reduces the amount of boilerplate code needed to handle command-line arguments in bash scripts.</p>
<h2 id="other-scripting-languages:-python-and-javascript" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other scripting languages: Python and JavaScript<a href="#other-scripting-languages:-python-and-javascript" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other scripting languages: Python and JavaScript"></a></h2>
<p>
Another automation approach that you might consider involves dynamic and interpreted languages such as <a href="https://www.python.org">Python</a> or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a>. If your team feels comfortable writing in these languages, they can be excellent options for automation tasks. Like Ruby (e.g., Fastlane), these languages run scripts instantly without a compilation step, and they provide access to extensive ecosystems of libraries—perhaps not as mobile-tailored as the ecosystem that Fastlane has built over the years, but still rich and diverse.</p>
<p>
You can leverage <a href="https://mise.jdx.dev">Mise</a> to provision the environment with the runtimes necessary to run these scripts, such as Node.js or Python, and use the package managers of those ecosystems to pull in the dependencies your scripts require. In the case of JavaScript, there are modern runtimes like <a href="https://deno.com">Deno</a> that take a dependency-resolution approach similar to swift-sh, where the dependencies are declared directly in the scripts themselves. For example:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
js    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="js">
#!/usr/bin/env -S deno run --allow-run --allow-read

const command = new Deno.Command(&quot;/usr/bin/xcrun&quot;, {
  args: [
    &quot;xcodebuild&quot;,
    &quot;-project&quot;,
    &quot;Automation/Automation.xcodeproj&quot;,
    &quot;-scheme&quot;,
    &quot;Automation&quot;,
    &quot;-destination&quot;,
    &quot;generic/platform=iOS&quot;,
    &quot;CODE_SIGNING_ALLOWED=NO&quot;,
    &quot;CODE_SIGNING_REQUIRED=NO&quot;,
    &quot;CODE_SIGN_IDENTITY=&quot;,
  ],
  cwd: new URL(&quot;.&quot;, import.meta.url).pathname,
  stdout: &quot;inherit&quot;,
  stderr: &quot;inherit&quot;,
});

const child = command.spawn();
const status = await child.status;
Deno.exit(status.code);    </shiki-highlight>
  </div>
</div>
<p>
JavaScript runtimes like Deno provide you with an extensive standard library and ecosystem of packages that rival what Fastlane offers through Ruby. They also benefit from the widespread familiarity of JavaScript among developers, making them accessible to team members who might not be Swift or Ruby experts.</p>
<h2 id="closing-words:-finding-your-automation-path" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words: Finding your automation path<a href="#closing-words:-finding-your-automation-path" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words: Finding your automation path"></a></h2>
<p>
There&#39;s no perfect solution that fits all projects and teams. If you value having access to a rich ecosystem of plugins specifically designed for mobile app development, then Fastlane might be your best choice. However, with LLMs now capable of generating automation code in languages that might otherwise be tedious to write, such as bash, Fastlane&#39;s plugins as units of encapsulation and reusability might not be as critical as they once were.</p>
<p>
This shifting landscape means you might want to lean toward the side of portability, which bash scripts can provide. But once again, with tools like Mise being able to provision environments quickly and reliably, portability becomes less of an issue because you can reasonably assume developers will have the right environment to run the script.</p>
<p>
What factors remain, then, in making your decision? The joy and efficiency of writing and maintaining those scripts is a significant consideration, which many teams might find in using Swift. With Swift, you&#39;d be trading away the instant launch time of interpreted languages, but hopefully, this is something that Apple will address in the future, meaning it won&#39;t be as much of an issue long-term. However, don&#39;t expect the immediate responsiveness of running a bash, Ruby, or Python script.</p>
<p>
Note that you can mix-and-match. For example, you can use Bash scripts for small workflows, and use Swift for more advanced ones such that you can leverage the expressiveness of the language. If you&#39;re curious about our approach at Tuist, we leaned into the portability and instant launch time of bash, while leveraging LLMs to help us write and maintain our scripts. This combination has proven effective for our specific needs and workflows.</p>
<p>
Our final advice: Don&#39;t feel tempted to simply adopt what everyone else is doing, and don&#39;t be afraid to pursue a path that feels unconventional for your team. The low-level building blocks have become more capable over the years, so some of the abstractions the community has settled on might no longer be necessary for your specific use case. You&#39;ll often be surprised by how far you can go with a simple bash script and an LLM helping you in the process.</p>
<p>
Regardless of which path you choose, we recommend leveraging <a href="https://mise.jdx.dev">Mise</a> to provision the environments that your scripts depend on, and <a href="/blog/2025/03/11/own-your-automation">owning your automation</a> such that it&#39;s not coupled to any particular platform. Remember: your automation belongs to your project and should serve your specific needs.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Shaping a one-stop shop for app developers ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We reflect on what we've learned and the vision that we have for Tuist and the role it'll play in the app development ecosystem. ]]></summary>
      <link href="https://tuist.dev/blog/2025/04/10/one-stop-shop"/>
      <id>https://tuist.dev/blog/2025/04/10/one-stop-shop</id>
      <updated>Thu, 10 Apr 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In October 2023, after 6 years helping teams with the challenges of Xcode projects, we formed a company in Germany to allow us to work full-time in what we like the most: helping app developers build build the best apps fast.</p>
<p>
It’s been over a year, during which we’ve worn many hats and learned a lot about what it takes to build a company. Throughout that time, we thought deeply about the future of app development, the challenges that are ahead of teams, and the shape the company and the product should take to stay relevant and elevate the experience of building apps. We love openness, more so when more teams and developers are making Tuist an indispensable tool in their toolchain, so what follows is an owed unfolding of the future that we are envisioning for Tuist. Let’s dive right in.</p>
<h2 id="from-first-line-to-lost-momentum" tabindex="-1" class="marketing__blog_post__body__content__heading">
From first line to lost momentum<a href="#from-first-line-to-lost-momentum" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to From first line to lost momentum"></a></h2>
<p>
Since the inception of mobile OSs like <a href="https://en.wikipedia.org/wiki/IOS">iOS</a> or <a href="https://en.wikipedia.org/wiki/Android_(operating_system)">Android</a>, the ecosystems have changed a lot. They offer many capabilities and manifest as many different platforms that developers are inclined to support to reach new audiences with their products. This growth, yet exciting, present developers with various needs and challenges that take the focus from the building momentum. From slow tooling to messing up with signing, or orchestrating a release, it’s just too much what a developer needs to hold in their heads when all they just want is to get the app out there and iterate.</p>
<p>
Organizations that can afford it, throw a platform team at the problem. Developers and teams that can’t, try to get through it by plumbing different open source tools together, a process that takes time and ongoing maintenance cost. In some cases the building momentum is so spoiled that organizations fork their native efforts by introducing a dynamic runtime like <a href="https://reactnative.dev/">React Native</a>’s that brings them hot-reloading and over-the-air updates bringing them the lost momentum.</p>
<p>
This is happening much earlier these days because of the broad set of products and platforms developers aspire to support from the early days of the project.</p>
<p>
We believe Tuist can be that platform team—just virtual.</p>
<h2 id="escaping-locally-scoped-state" tabindex="-1" class="marketing__blog_post__body__content__heading">
Escaping locally-scoped state<a href="#escaping-locally-scoped-state" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Escaping locally-scoped state"></a></h2>
<p>
Unlike other ecosystems like the web, mobile has traditionally taken a local-first approach to tooling. Tools would run in an environment and the state, if any, would be scoped to that environment, which in the case of CI would get disposed on completion. This works for some workflows, like having a script that archives and exports an app signing it, but at certain point, you need state to escape that locality. Otherwise your ability to improve your dev environment is limited. For example, how do you know if your build times are getting better or worse if you can’t track them over time? Or how do you know if you have flaky tests in your suite if you can’t track consecutive results of the same test? With local-only tooling, you can&#39;t.</p>
<p>
Moreover, development of apps is not isolated within your Xcode environment. You most likely collaborate with your peers through tools like <a href="https://github.com">GitHub</a>, <a href="https://slack.com">Slack</a>, or <a href="https://linear.app">Linear</a>. Taking a more holistic approach to dev tooling makes it possible to build integrations that otherwise would not be possible, like clicking on a link that you received automatically in Slack and seeing the app launching right there. That’s when the magic starts.</p>
<p>
When state escapes a local environment, we need to persist it in a shared space, and that naturally leads to a server and a storage solution that allows tracking the evolution of state over time and the dependencies between different pieces of state. Additionally, the server can do processing asynchronously, escaping the synchronous act of generating the state, and can interface with other services via HTTP or be interfaced. It unlocks a world of opportunities in enabling that virtual platform team that can provide you with top-notch experiences.</p>
<p>
For many years, CI was the only server-side tooling mobile tools used. Some companies built open-source solutions that required a server too, and most recently, we are seeing more open source hapenning in the space (e.g. <a href="https://github.com/tramlinehq">Tramline</a>). We think this is great news for the ecosystem.</p>
<p>
However, placing local state behind a company’s wall also means making the company behind that server the owner of your state.
This is not necessarily an issue, but as we have seen in the past with many services,
which ended up <a href="https://en.wikipedia.org/wiki/Enshittification">enshittifying</a> and doing things like changing their terms to open new revenue streams with your data,
or forcing you to abusive pricing through vendor-locking,
the server-side dev tools are not free from these practices.
In simple terms,
companies reach a ceiling in a market that gets more and more saturated,
so they try to squeeze more money out of you,
and they are willing to do anything to get it.
The product and you don&#39;t matter anymore.</p>
<p>
At Tuist we agreed that we wanted to do things differently creating a framework that would prevent this from happening.
Let me tell you about it.</p>
<h2 id="shifting-value-from-software-to-infrastructure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Shifting value from software to infrastructure<a href="#shifting-value-from-software-to-infrastructure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Shifting value from software to infrastructure"></a></h2>
<p>
Businesses consist of producing value and capturing part of that value that they produce.
In the case of companies that have proprietary software,
they try to capture as much value as they can relative to the value that they produce.
But as we all know, <a href="https://pepicrft.me/blog/2025/03/31/software-commoditizes">software and infrastructure</a> commoditizes,
and we are starting to see that in the <a href="https://pepicrft.me/blog/2025/03/25/mobile-ci-is-plateauing">Mobile CI</a> space,
where new players propose lower margins pushing the prices down for everyone.
This is when you start to see companies exploiting their leverage to squeeze more money out of you.
The thing is, that it doesn&#39;t need to be like that.</p>
<p>
There&#39;s another type of company: open source companies.
Unlike closed-source companies, they can produce insanely more value than the proprietary companies because they get contributions from the community.
Think about it, if your proprietary-software company is 5 developers,
you are limited to the capacity of those 5 developers, potentially improved with AI technologies and agents.
You get it.
Compare that to a world of developers that might go the extra mile to contribute to the project because they believe in the mission.
Not only this is good from the perspective of the ability to produce more value,
but also the diversity of ideas that are coming to the project.
If your 5 developers are based in some country,
then your vision of the world will be very limited to the vision of the world from that country.
Now, if you are getting contributions from many countries, it opens your perspective of the world.
This morning I was listening to <a href="https://podcasts.apple.com/cz/podcast/react-native-radio/id1058647602?i=1000702255560">this podcast</a> with <a href="https://www.tramline.app/blog-author/pratul-kalia">Pratul Kalia</a> about <a href="https://www.tramline.app/">Tramline</a> and it made me realize how myopic we might be regarding what&#39;s happening in the world. In particular, he talks about the lag between India and the US, and how the focus on mobile took a bit more years to arrive to India.
In the case of Tuist, we are working a lot lately with communities in Japan and South Korea, which is introducing us to a world of ideas and opportunities that will lead to a much better product.</p>
<p>
<strong>Open source companies capture way less value, often none, but since the value that they produce is much more</strong>, the net is higher than their proprietary counterparts.
Open source companies play more of a long-term game, and not only address building a better product, who doesn&#39;t want that, but also minimizes the risk of enshittification.</p>
<p>
If you open your software and permissively license it, 
decisions are made in public with the community.
Any decision that would go against the values of the project or the community will be met with resistance.
And if those decisions happen,
like we&#39;ve seen with projects like <a href="https://www.terraform.io/">Terraform</a>,
the community quickly gathers, forks the project, and continues <a href="https://opentofu.org/">its development</a> in the same spirit.</p>
<p>
If we are building a virtual platform team, a one-stop shop for app developers, it must be open source.
There&#39;s no other way, but that requires us to shift the capturing the value from the software itself, from somewhere else.</p>
<h2 id="shifting-capturing-of-value-from-software-to-infrastructure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Shifting capturing of value from software to infrastructure<a href="#shifting-capturing-of-value-from-software-to-infrastructure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Shifting capturing of value from software to infrastructure"></a></h2>
<p>
Most of the value that we are capturing these days is through the software itself.
Hence why part of our software is not open source.
If we open sourced everything, we wouldn&#39;t be able to capture any value and therefore the company and the project would die, which is not something we want.
So we need to draw a line somewhere.
We are still figuring out what the right place is, but we believe it&#39;ll be a mix of infrastructure,
or in other words you pay us for a service that&#39;s fast, reliable, and available every day of the year, and we scale it based on your usage,
and features that are tailored to the needs of large enterprises,
which are usually the ones that can afford to pay for them.</p>
<p>
As we add more capabilities to the platform, something which I&#39;ll talk about soon, hosting Tuist will become more complex.
We won&#39;t make it complex intentionally, because it&#39;ll be unnecessarily complex for us too,
but there&#39;ll be complexity that will get in the way, and that we&#39;ll develop a muscle to manage it at low-cost.
Think of <a href="https://supabase.com/">Supabase</a>. At the core there&#39;s a <a href="https://www.postgresql.org/">Postgres</a> database. 
But many companies, including us, pay them for hosting and scaling the database because what we want is building products,
not managing and scaling databases.
Think of Tuist the same way,
<strong>you&#39;ll want to be building your apps, not managing a service that helps you streamline the process.</strong>
And here&#39;s another thing, because it builds on an open source commodity,
you can&#39;t go the path of abusive pricing, so prices will naturally be more fair than any other proprietary solution.</p>
<p>
And what about everyone else that will host it for free?
That&#39;s great news for us. We don&#39;t expect them to contribute capital.
Financial capital is not the only form of capital.
They&#39;ll contribute ideas, bugs, fixes, and share the word out there.
They&#39;ll act as a marketing machine and help the product better every day.
It&#39;s another form of capital.</p>
<p>
When will that happen? When we&#39;ve shifted enough value capturing to infrastructure such that organizations are willing to pay for it.</p>
<p>
Alright...we need a server to further streamline development, a server brings a world of opportunities for developer experiences, and we are going to bet on openness to build a reliable piece of software that companies can safely build upon. Let&#39;s talk about the product itself and how we see developer experience getting better.</p>
<h2 id="product" tabindex="-1" class="marketing__blog_post__body__content__heading">
Product<a href="#product" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Product"></a></h2>
<p>
Our north star developer experience for Tuist is that <strong>you&#39;ll be able to plug your account on Tuist with a repository in your organization, and that&#39;s it.</strong> We&#39;ll come with sensible overridable defaults such that you don&#39;t have to do any configuration work most of the time. This is something that <a href="https://techcrunch.com/2018/01/02/apple-buys-app-development-service-buddybuild/">BuddyBuild</a> pioneered at the time when they proposed that pipeline YAMLs could be optional.
<strong>They must be.</strong></p>
<p>
Over the years we&#39;ve developed extensive knowledge over Xcode projects, so I strongly believe we are well positioned to build a zero-configuration developer experience. Moreover, we are going to take the idea a bit further, and we are going to make workflows triggerable through the UI. As you might have noticed, most of the workflows on mobile are CI-centric. There&#39;s a reason for that, virtualizing workflows remotely is costly, so costly that only CI companies have access to that, but we plan to change that. A developer should be able to create a new preview from any commit by just clicking a button, and once again, there should be no pipeline for that. We should be able to leverage the same capability to sign the apps for the users generating the right certificates and profiles for that. We&#39;ll sign on the fly. Signing will be an implementation detail that they won&#39;t have to think about anymore.</p>
<p>
And because we&#39;ll invest in reducing the cost of virtualization, we believe it&#39;s time to reduce the indirection between Git forges (e.g. GitHub and GitLab). We&#39;ll provide cheap runners so that you don&#39;t have to move away from GitHub Actions or GitLab CI. And if you bring your <a href="https://aws.amazon.com/">AWS</a> or <a href="https://www.scaleway.com/en/">Scaleway</a> account, we orchestrate the provisioning so that their cost is tied to your cost account. And obviously, if you want, we&#39;ll provide those runners.</p>
<p>
We&#39;ll look at app development more holistically. First broadening the phases of app development that we help teams with, including project creation, and app releasing. And why not, very far into the future we might integrate with analytics and error tracking platforms to help you have an insight into how your app is performing. We are building the infrastructure for that. </p>
<p>
Then, we&#39;ll extend to other app ecosystems, like Android. <strong>The problems that we are solving are not specific to one ecosystem.</strong> The solutions might be, but we are putting a strong focus on ensuring the design is not that strongly coupled to the Apple platform. We are doing so because organizations have shared that they&#39;d prefer to have <em>one-tool-to-rule-them-all</em>, and we believe we are very well positioned to deliver on that. And I believe that our bet on open source plays nicely with this idea because we can collaborate on bringing Tuist to new ecosystems. It&#39;ll require a good amount of social capital investment to make that happen, but once we get the ball rolling, we can plug the Tuist server into any app ecosystem.</p>
<p>
<strong>We&#39;ll continue maintaining the solution that gave birth to Tuist, project generation</strong>, a feature many of our developers use and love, and upon which we can deliver optimizations such as caching, but we hope Apple gets those problems fixed at a lower level, which means we can plug directly into the foundations and add a layer of useful optimizations and utilities.</p>
<p>
Open source won&#39;t be our unique strength. We are doubling down on our design.
Many developer tools treat design as an afterthought. We are making it core and center.
Tuist needs to feel like an enticing product that you want to have in your toolchain.
Not only that, but we are building a design system such that when we open source the server,
developers can use our pre-made components and design file to design their own features and contribute them to our server codebase.
In other words, we are designing Tuist in a way where we take more of a steering role, providing guidance, and ensuring the building blocks are well-designed to enable collaboration and contribution.</p>
<p>
We&#39;ll also double down on <a href="https://en.wikipedia.org/wiki/Telemetry">telemetry</a>, something that&#39;s not common in the app ecosystem.
Apps and processes can&#39;t be optimized without data.
First, we are going to build open source tools to help with data collection.
Second we are going to standardize them and make it available from a server through an <a href="https://tuist.dev/api/docs">API</a>.
You can consume it from a Prometheus backend, or build your own client.
There&#39;ll be a well-documented and productized API for you to use.
And we&#39;ll provide a UI that will make the data actionable helping you make decisions,
in some cases make decisions for you,
and provide the information in a data such that you can use it to contextualize your conversations with LLM technologies.</p>
<h2 id="we-are-building-the-public-infrastructure-for-productive-app-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
We are building the public infrastructure for productive app development<a href="#we-are-building-the-public-infrastructure-for-productive-app-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to We are building the public infrastructure for productive app development"></a></h2>
<p>
As more developers embark on the journey of building apps—whether as entrepreneurs or as part of the companies they join—it&#39;s increasingly important that the tools they rely on are accessible and part of a shared commons that can be collaboratively developed.</p>
<p>
This belief is what drives us every day at Tuist. We’re not here to build private clubs for the few—we’re here to create public parks for the many.</p>
<p>
Openness and open source are foundational to realizing that vision. We approach openness with curiosity and conviction, seeing it as the most powerful lever for building the toolchain we believe the app development world needs.</p>
<p>
We see a clear need for a one-stop shop for app development. Just as dashboards have <a href="https://grafana.com/">Grafana</a>, metrics have <a href="https://prometheus.io/">Prometheus</a>, and Postgres has <a href="https://supabase.com/">Supabase</a>, <strong>app development will have Tuist.</strong></p>
<p>
We’re not in a rush. We have the resources and the long-term commitment to make this vision real. And we&#39;re on the right path.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Keeping your Swift apps' sensitive data secret ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn how to safely share and use sensitive data in your Swift apps. ]]></summary>
      <link href="https://tuist.dev/blog/2025/04/09/secrets"/>
      <id>https://tuist.dev/blog/2025/04/09/secrets</id>
      <updated>Wed, 09 Apr 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When you build Swift apps,
you might need to use or include sensitive data within your app.
For example, API keys, or the certificate for signing the app.
This is information that you don&#39;t want to include raw in your repository.
What most teams do is include it as a secret in their CI/CD environment,
and read its value through environment variables.
However,
if the need for debugging automation arises,
this makes debugging automation a bit more difficult,
since a trusted subject (e.g. the lead of the team) can&#39;t easily access the values.</p>
<p>
<a href="https://docs.fastlane.tools/actions/match/">Fastlane Match</a> proposed a solution for this in the context of certificates and provisioning profiles.
What if they are encrypted under a private key in the same repository or in a separate repository that all the developers have access to?
This is an approach similar to <a href="https://guides.rubyonrails.org/security.html#custom-credentials">credentials</a> in <a href="https://rubyonrails.org/">Ruby on Rails</a>, which allows having a YAML file with encrypted values that the framework can automatically decrypt and expose at runtime when a private key is available.
Wouldn&#39;t it be awesome if we could generalize Match&#39;s approach to work not only with certificates and provisioning profiles,
but also with other sensitive data?
Let us tell you that this is indeed possible thanks to <a href="/blog/2025/02/04/mise">Mise</a>, a tool that we already talked about in the past.
We&#39;ll guide you through how to set it up, and give you some examples of how to use it to encrypt certificates, and expose and obfuscate information into your apps. Let&#39;s dive right into it!</p>
<h2 id="setting-up-your-"secret"-environment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Setting up your &quot;secret&quot; environment<a href="#setting-up-your-"secret"-environment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Setting up your "secret" environment"></a></h2>
<p>
<a href="https://mise.jdx.dev/">Mise</a> is a frontend to your dev env. It might be the first time that you might have heard of this concept, but you can think of it as a tool that takes care of the things that you need for development, from provisioning the environment with the tools that your project needs, to dynamically configuring the environment with environment variables that you need to work on the project.</p>
<p>
One of the features that they provide is <a href="https://mise.jdx.dev/environments/secrets.html">secrets</a>. They can decrypt secrets that are encrypted using a private key, and expose them in the environment as environment variables. The solution builds upon <a href="https://getsops.io/">sops</a>, a tool that solves encrypting and decrypting configuration files (e.g., YAML, ENV, JSON), and <a href="https://github.com/FiloSottile/age">age</a>, a tool to generate keypairs to use with sops.</p>
<p>
The first thing that we&#39;ll need to do is installing both sops and age. We recommend pinning the version in your project&#39;s <code class="inline">mise.toml</code> file instead of installing them globally. Edit the file, and add the tools under the <code class="inline">tools</code> section:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[tools]
# ...Other tools
&quot;sops&quot; = &quot;3.9.3&quot;
&quot;age&quot; = &quot;1.2.1&quot;    </shiki-highlight>
  </div>
</div>
<p>
Then run <code class="inline">mise install</code> to install the tools and make them available. The next step is to generate the keypair that we&#39;ll use to encrypt secrets. Run the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
age-keygen -o ~/.config/mise/my-project-age.txt    </shiki-highlight>
  </div>
</div>
<p>
We recommend prefixing the key with the name of your project or organization such that you can have multiple keys in your environment that can have a very granular scope, for example a single project, or a more generic organization-wide key. The command will output a file containing the private and the public key:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# created: 2025-04-03T10:30:44+02:00
# public key: age16wnlakxsqk6k627jn5vuv3kk75jdnfpn5eg8sghrw0yj6ehxlsgqx864sd
AGE-SECRET-KEY-1F7VFL7PF90Z2TEMKTXX9KJR5LUVNR45T7W3586WJKUME40JXQUCS9EKGN8    </shiki-highlight>
  </div>
</div>
<p>
The last line represents your private key so keep it in a secure place and make sure you only expose it in trusted environments.</p>
<p>
Once we have the key, the next thing we&#39;ll need is a file that will contain the secrets that we want to encrypt, and a couple of scripts to encrypt the file and edit the encrypted content. Let&#39;s start with the file containing the secrets by creating a <code class="inline">.env.json</code> file at the root with an empty JSON object:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
json    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="json">
{}    </shiki-highlight>
  </div>
</div>
<p>
Then we are going to create two <a href="https://mise.jdx.dev/tasks/">Mise tasks</a> for encrypting and editing. The first one will be at <code class="inline">mise/tasks/env/encrypt.sh</code>. Create the file with the following content:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env bash
# mise description=&quot;Encrypts the .env file&quot;

set -eo pipefail

sops encrypt -i --age &quot;age16wnlakxsqk6k627jn5vuv3kk75jdnfpn5eg8sghrw0yj6ehxlsgqx864sd&quot; .env.json    </shiki-highlight>
  </div>
</div>
<p>
Where the value passed through <code class="inline">--age</code> is the public key generated. Make sure you replace it with yours. The second task will be at <code class="inline">mise/tasks/env/edit.sh</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env bash
# mise description=&quot;Edit the .env file&quot;

set -eo pipefail

SOPS_AGE_KEY_FILE=~/.config/mise/my-project-age.txt sops edit .env.json    </shiki-highlight>
  </div>
</div>
<p>
Similarly, make sure that <code class="inline">SOPS_AGE_KEY_FILE</code> points to the file where you&#39;ve decided to persist the key in development environments.</p>
<p>
Make sure that you set executable permissions for the <code class="inline">encrypt.sh</code> and <code class="inline">edit.sh</code> scripts:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
chmod +x mise/tasks/env/encrypt.sh
chmod +x mise/tasks/env/edit.sh    </shiki-highlight>
  </div>
</div>
<p>
And then run <code class="inline">mise run env:encrypt</code> to encrypt the <code class="inline">.env.json</code> file. The last step needed to expose the secrets as environment variables is to add the following configuration to the <code class="inline">mise.toml</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[env]
_.file = &quot;.env.json&quot;

[settings]
sops.age_key_file = &quot;~/.config/mise/my-project-age.txt&quot; # The path to your key    </shiki-highlight>
  </div>
</div>
<p>
Mise will automatically decrypt and expose the content from <code class="inline">.env.json</code> into the environment, so you can access the secrets using env. variables.</p>
<h2 id="editing-the-encrypted-file" tabindex="-1" class="marketing__blog_post__body__content__heading">
Editing the encrypted file<a href="#editing-the-encrypted-file" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Editing the encrypted file"></a></h2>
<p>
You might have noticed that we added a Mise task called <code class="inline">env:edit</code> to edit the encrypted file. Run the following command to edit the file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
EDITOR=&quot;code --wait&quot; mise run env:edit    </shiki-highlight>
  </div>
</div>
<p>
You can replace <code class="inline">code</code> with your editor of choice (e.g. <code class="inline">zed</code>, <code class="inline">cursor</code>). The task will open the editor with an unencrypted version of the file and block the process until the edition finishes. On close, the process will then encrypt your changes automatically. Isn&#39;t that magic? Try to add some content to it, save it, and then close. For example:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
json    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="json">
{
  &quot;HELLO&quot;: &quot;WORLD&quot;
}    </shiki-highlight>
  </div>
</div>
<p>
If you then run <code class="inline">echo $HELLO</code>. You&#39;ll notice that the variable is exposed in the environment.</p>
<h2 id="continuous-integration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Continuous integration<a href="#continuous-integration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Continuous integration"></a></h2>
<p>
Alright, we&#39;ve got a setup to encrypt, decrypt, and edit sensitive data, which works if we have a key in the file-system, but what about CI environments where the key is not available in a file. In those environments you&#39;ll have to expose it as an environment variable <code class="inline">MISE_SOPS_AGE_KEY</code>. Just copy the value, and expose it in trusted CI environments. We recommend that you only do it in the steps that need to access the sensitive data to reduce the security risk.
When invoking your automation through Mise tasks, you can assume the environment variables will be present:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mise run release    </shiki-highlight>
  </div>
</div>
<p>
There&#39;s an interesting side effect of using this approach to encrypting secrets. As we touched on in <a href="/blog/2025/03/11/own-your-automation">Own your Swift apps&#39; automation</a>, secret management is one of the features that CI providers offer and that creates vendor lock-in with them.
Thanks to this, you can reduce the number of secrets that you expose to just one, the sops private key,
and not only that, but you can use Git to keep track of the changes in the secrets. You won&#39;t see the value changes because they are encrypted, but you can use commit messages to track for example that &quot;certificate x renovated due to expiration&quot;.
Git is a powerful tool that gives you a record of changes for free, so moving away from it is generally a bad idea.</p>
<h2 id="use-case-1---encrypting-certificates" tabindex="-1" class="marketing__blog_post__body__content__heading">
Use case 1 - Encrypting certificates<a href="#use-case-1---encrypting-certificates" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Use case 1 - Encrypting certificates"></a></h2>
<p>
The most common use case for encrypting sensitive data is &quot;certificates&quot; that workflows might need to use for signing the app for distribution. As mentioned earlier, teams have traditionally used <a href="https://docs.fastlane.tools/actions/match/">Match</a> for that and automating the generation of certificates and profiles. If you only need it for just encrypting files, you might not need Match at all.</p>
<p>
As you probably know, the signing certificate, containing the public and the private key, is typically a <code class="inline">.p12</code> file. So how do we get that into our <code class="inline">.env.json</code> file if all we have is a file? Easy, you can Base64 its content:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
base64 -o - -i /path/to/certificate.p12 | pbcopy    </shiki-highlight>
  </div>
</div>
<p>
Ensure that when you export the certificate from the Keychain by doing right-click on the certificate, it also includes the private key. In Keychain&#39;s UI you&#39;ll notice if you click on the certificate it&#39;ll show a dropdown with the private key.</p>
<p>
Once you have the certificate in the pasteboard, you can run the edit command, and then place it in the encrypted <code class="inline">.env.json</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
json    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="json">
{
  &quot;BASE_64_CERTIFICATE&quot;: &quot;&lt;BASE64_ENCODED_CERTIFICATE&gt;&quot;,
  &quot;CERTIFICATE_PASSWORD&quot;: &quot;&lt;PASSWORD&gt;&quot;
}    </shiki-highlight>
  </div>
</div>
<p>
You can verify that the content is available by echoing it <code class="inline">echo $BASE_64_CERTIFICATE</code>.</p>
<p>
The next step in the workflow that needs the certificate is to decode it and install it in the Keychain. If the script runs locally, you can use the default keychain. When that happens, you&#39;ll likely get a prompt from the system asking for your password to install the certificate. In CI, it&#39;s recommended to create a temporary keychain to avoid issues with prompts and permissions. You can use the following code snippet:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
TMP_DIR=/private$(mktemp -d)
trap &quot;rm -rf $TMP_DIR&quot; EXIT # Delete on exit

if [ &quot;${CI:-}&quot; = &quot;true&quot; ]; then
    echo &quot;Creating a temporary keychain&quot;
    KEYCHAIN_PASSWORD=$(uuidgen)
    KEYCHAIN_PATH=$TMP_DIR/certificates/temp.keychain
    security create-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
    security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
    security default-keychain -s $KEYCHAIN_PATH
    security unlock-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
fi

echo $BASE_64_CERTIFICATE | base64 --decode &gt; $TMP_DIR/certificate.p12 &amp;&amp; security import $TMP_DIR/certificate.p12 -P $CERTIFICATE_PASSWORD -A    </shiki-highlight>
  </div>
</div>
<p>
Note that the above step might be optional since some CI providers already do it for you.</p>
<p>
That&#39;s really all you need. Xcode&#39;s build system, which uses the <code class="inline">codesign</code> tool internally, should be able to look up the certificate in the Keychain and use it for signing. Isn&#39;t it amazing that we replicated the core-most piece of functionality that Match provides?</p>
<h2 id="use-case-2---encrypting-runtime-data" tabindex="-1" class="marketing__blog_post__body__content__heading">
Use case 2 - Encrypting runtime data<a href="#use-case-2---encrypting-runtime-data" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Use case 2 - Encrypting runtime data"></a></h2>
<p>
The second common use case in app development is encrypting runtime data. For example, you&#39;ve got an API key to initialize an SDK or interact with your backend services, and you don&#39;t want to include that raw in your app&#39;s <code class="inline">Info.plist</code>. You might want to obfuscate them, but how do you pass the environment variable all the way to the build system to obfuscate its value at build time?</p>
<p>
First, you&#39;ll need a tool to obfuscate the data at compile-time so that the value can&#39;t be easily read from the binary. For that, you can use the <a href="https://github.com/p-x9/ObfuscateMacro">ObfuscateMacro</a>. Add it to your project as a dependency and then create a static value:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ObfuscateMacro

struct Secrets {
  static let apiKey = #ObfuscatedString(&quot;SECRET_API_KEY&quot;)
}    </shiki-highlight>
  </div>
</div>
<p>
Note in the code snippet that we hardcoded the value, which is not what we want. The secret is an environment variable, which we need to somehow pass to the compiler. Unfortunately, Xcode&#39;s build system nor Swift Macros have that capacity, therefore you&#39;ll have to run a script before the build process to generate the values. </p>
<p>
To simplify the process, we created <a href="https://gist.github.com/pepicrft/a692d44abf72df96c7bcd12c1e7bbc75">that script</a> which does that automatically for all the environment variables whose name starts with <code class="inline">SECRET_</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env bash
# mise/tasks/env/generate-secrets.sh

set -eo pipefail

# Check if output file argument is provided
if [ -z &quot;$1&quot; ]; then
  echo &quot;Usage: $0 &lt;output_file_path&gt;&quot;
  exit 1
fi

OUTPUT_FILE=&quot;$1&quot;

mkdir -p &quot;$(dirname &quot;$OUTPUT_FILE&quot;)&quot;

{
  echo &#39;import ObfuscateMacro&#39;
  echo &#39;&#39;
  echo &#39;struct Secrets {&#39;
} &gt; &quot;$OUTPUT_FILE&quot;

env | while IFS=&#39;=&#39; read -r key value; do
  if [[ &quot;$key&quot; == SECRET_* ]]; then
    base_key=&quot;${key#SECRET_}&quot;
    camel_case_key=&quot;$(echo &quot;$base_key&quot; | awk &#39;{
      split(tolower($0), parts, &quot;_&quot;);
      result = parts[1];
      for (i = 2; i &lt;= length(parts); i++) {
        result = result toupper(substr(parts[i],1,1)) substr(parts[i],2);
      }
      print result;
    }&#39;)&quot;

    echo &quot;  static let $camel_case_key = #ObfuscatedString(\&quot;$value\&quot;)&quot; &gt;&gt; &quot;$OUTPUT_FILE&quot;
  fi
done

echo &#39;}&#39; &gt;&gt; &quot;$OUTPUT_FILE&quot;    </shiki-highlight>
  </div>
</div>
<p>
Create the script at <code class="inline">mise/tasks/env/generate-secrets.sh</code> and assign executable permissions with <code class="inline">chmod +x mise/tasks/env/generate-secrets.sh</code> and then invoke it with <code class="inline">mise run env:generate-secrets Sources/Secrets.swift</code>. Make sure you replace <code class="inline">Sources/Secrets.swift</code> with the path where you plan to keep your secrets, and the file is included in the project target from where you plan to read them. Note that you&#39;ll need a placeholder that you can run in development, so I recommend setting development values, and when doing releases, override using the script.</p>
<p>
You&#39;ll then have to adjust the automation from secret environments to run the script before building the project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Generate the secrets file
# Build/archive the project    </shiki-highlight>
  </div>
</div>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
Note that this only covers part of the security. You&#39;ll have to make sure the information is not included in visible parts of the requests, for example the URL, making it easily accessible by any malicious actor.
You&#39;d be surprised how many apps include sensitive data in their <code class="inline">Info.plist</code>, and how easy it is to impersonate them from a different application. Imagine populating <a href="https://firebase.google.com/">Firebase</a> analytics pretending to be a different app.
Now you no longer have excuses to add an extra layer of safety to your apps. You won&#39;t regret it in the future.</p>
<blockquote>
  <p>
Check out <a href="https://github.com/tuist/secrets-in-swift-app">this repository</a> which contains an Xcode project exemplifying this setup.  </p>
</blockquote>
<h2 id="updates" tabindex="-1" class="marketing__blog_post__body__content__heading">
Updates<a href="#updates" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Updates"></a></h2>
<ul>
  <li>
The post was updated on April 10th 2025 to suggest including the <code class="inline">generate-secrets.sh</code> script in the repo over piping the <code class="inline">curl</code> output through bash, which is unsafe.  </li>
</ul>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist is now SOC 2 Type II compliant ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We are thrilled to announce that Tuist is now SOC 2 Type II compliant ]]></summary>
      <link href="https://tuist.dev/blog/2025/04/03/soc2"/>
      <id>https://tuist.dev/blog/2025/04/03/soc2</id>
      <updated>Thu, 03 Apr 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
SOC Type II compliance is a big step in proving our commitment to security and reliability. Whether you’re using Tuist to manage Xcode projects, streamline development, or handle sensitive data, you can trust that we take security seriously.  </p>
<p>
Unlike SOC 2 Type I, which is a one-time assessment, <strong>Type II requires us to demonstrate consistent security practices over several months</strong>. This means our security isn’t just a snapshot—it’s baked into how we operate every day.  </p>
<p>
Here’s why we pursued SOC 2, how we tackled compliance, and what we learned along the way.  </p>
<h2 id="why-go-for-soc-2?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why go for SOC 2?<a href="#why-go-for-soc-2?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why go for SOC 2?"></a></h2>
<p>
Security isn’t just a nice-to-have—it’s a necessity. As more teams adopted Tuist, we found ourselves answering security questionnaires and explaining our security measures over and over again. We wanted a <strong>clear, industry-recognized way to show that we handle your data responsibly</strong>.  </p>
<p>
SOC 2 helps with that. It’s designed for SaaS companies like us and focuses on the security and privacy of customer data. Achieving compliance means we’ve implemented strong controls and had them independently verified.  </p>
<p>
Another reason we started early? <strong>Future-proofing.</strong> Security is easiest when it’s built into a company’s DNA. Instead of scrambling to meet compliance as we scale, we’re setting a strong foundation now—so security never becomes an afterthought.  </p>
<h2 id="what-is-soc-2-type-ii?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is SOC 2 Type II?<a href="#what-is-soc-2-type-ii?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is SOC 2 Type II?"></a></h2>
<p>
SOC 2 is a security and compliance framework developed by the <strong>American Institute of CPAs (AICPA)</strong>. It evaluates companies on five Trust Services Criteria:  </p>
<ul>
  <li>
<strong>Security</strong> – Protecting systems and data from unauthorized access.    </li>
  <li>
<strong>Availability</strong> – Ensuring services are reliable and accessible.    </li>
  <li>
<strong>Processing Integrity</strong> – Making sure systems operate as expected.    </li>
  <li>
<strong>Confidentiality</strong> – Safeguarding sensitive data.    </li>
  <li>
<strong>Privacy</strong> – Managing personal data responsibly.    </li>
</ul>
<p>
SOC 2 has two types of audits:  </p>
<ul>
  <li>
<strong>Type I</strong> – A one-time assessment of security policies and controls.    </li>
  <li>
<strong>Type II</strong> – A long-term audit (6–12 months) proving those controls are consistently followed.    </li>
</ul>
<p>
We went for <strong>Type II</strong> because we didn’t just want to pass a one-time check—we wanted to show we take security seriously, every day.  </p>
<h2 id="picking-the-right-compliance-tool" tabindex="-1" class="marketing__blog_post__body__content__heading">
Picking the right compliance tool<a href="#picking-the-right-compliance-tool" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Picking the right compliance tool"></a></h2>
<p>
We needed a compliance tool that worked well with our stack—<a href="https://supabase.com/">Supabase</a>, <a href="https://github.com/">GitHub</a>, <a href="https://workspace.google.com/">Google Workspace</a>, and <a href="https://www.tigrisdata.com/">Tigris</a>. After evaluating:  </p>
<ul>
  <li>
<a href="https://www.vanta.com/">Vanta</a>    </li>
  <li>
<a href="https://drata.com/">Drata</a>    </li>
  <li>
<a href="https://tugboatlogic.com/">Tugboat Logic</a>    </li>
</ul>
<p>
We landed on <strong>Vanta</strong>. It had the best automation, worked smoothly with our existing tools, and didn’t require overly intrusive permissions (some alternatives wanted full GitHub access—not happening).  </p>
<h2 id="finding-the-right-auditor" tabindex="-1" class="marketing__blog_post__body__content__heading">
Finding the right auditor<a href="#finding-the-right-auditor" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Finding the right auditor"></a></h2>
<p>
Once we had Vanta set up and running, we needed an independent auditor to review our security practices. Vanta connected us with several options, and we picked one that specializes in SaaS security audits.  </p>
<p>
The process started with a <strong>scoping call</strong>, where we determined which systems and processes would be reviewed. Then, we set a date for the audit’s <strong>Type II snapshot</strong>—a point in time that proves our policies were in place and working as intended.  </p>
<h2 id="preparing-for-the-audit" tabindex="-1" class="marketing__blog_post__body__content__heading">
Preparing for the audit<a href="#preparing-for-the-audit" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Preparing for the audit"></a></h2>
<p>
The months leading up to the audit were all about <strong>proving that security was part of our daily workflow</strong>. Vanta’s osquery agent helped us track:  </p>
<ul>
  <li>
<strong>Device security</strong> – Ensuring all company laptops had encryption, screen locks, and proper access controls.    </li>
  <li>
<strong>Policy enforcement</strong> – Creating and refining security policies for access control, data management, and asset tracking.    </li>
  <li>
<strong>Compliance checks</strong> – Verifying we had proper logging, monitoring, and security controls in place.    </li>
</ul>
<p>
Another key step was reviewing our vendor security. If we were being audited, we wanted our vendors to meet the same standards. So we asked for <strong>SOC 2 reports</strong> from any service we relied on that handled sensitive data.  </p>
<h2 id="open-security-policies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Open security policies<a href="#open-security-policies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Open security policies"></a></h2>
<p>
We believe in transparency, which is why we’ve made our security policies <strong>public</strong> in the <a href="https://handbook.tuist.dev">Tuist Handbook</a>.  </p>
<p>
This includes:  </p>
<ul>
  <li>
How we manage access control.    </li>
  <li>
How we protect user and project data.    </li>
  <li>
Our incident response process.    </li>
</ul>
<p>
Security shouldn’t be a black box. By sharing our policies, we make it clear how we operate and hold ourselves accountable to our users.  </p>
<h2 id="making-soc-2-work-for-us" tabindex="-1" class="marketing__blog_post__body__content__heading">
Making SOC 2 work for us<a href="#making-soc-2-work-for-us" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Making SOC 2 work for us"></a></h2>
<p>
One thing we didn’t want? <strong>Mindless checkbox compliance.</strong> Every security control we implemented had to make sense for Tuist—not just to satisfy an auditor.  </p>
<p>
For example:  </p>
<ul>
  <li>
<strong>Access Reviews</strong> – Instead of a rigid quarterly review, we built security checks into our onboarding/offboarding process to ensure permissions stay up to date.    </li>
  <li>
<strong>Incident Response</strong> – Rather than a generic playbook, we tailored our process to match how we actually work and respond to security events.    </li>
  <li>
<strong>Security Training</strong> – We kept it practical. Sure, we still had to sit through the “don’t reuse passwords” training video, but we focused on <strong>real security risks</strong> our team faces.    </li>
</ul>
<h2 id="launching-the-tuist-security-center" tabindex="-1" class="marketing__blog_post__body__content__heading">
Launching the Tuist Security Center<a href="#launching-the-tuist-security-center" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Launching the Tuist Security Center"></a></h2>
<p>
We’re also launching the <strong><a href="https://security.tuist.dev">Tuist Security Center</a></strong>, a hub where you can:  </p>
<ul>
  <li>
Learn how we protect your data.    </li>
  <li>
Request a copy of our SOC 2 audit report.    </li>
  <li>
Get in touch with our security team at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a>.    </li>
</ul>
<p>
Security is an ongoing effort, not a one-time project. We’ll continue improving our security posture, refining our processes, and making sure Tuist stays a trusted tool for developers everywhere.  </p>
<p>
If you’re working toward SOC 2 yourself, we hope this breakdown helps. It’s a big effort, but it’s worth it—not just for compliance, but for building a truly secure product. 🚀</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Transform your LLM into an Xcode project copilot ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Master your projects with the Tuist CLI MCP server by leveraging LLMs. ]]></summary>
      <link href="https://tuist.dev/blog/2025/04/03/mcp"/>
      <id>https://tuist.dev/blog/2025/04/03/mcp</id>
      <updated>Thu, 03 Apr 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Since its inception, Tuist has placed a strong emphasis on understanding Xcode projects and workspaces, helping teams manage them by conceptually simplifying their complexities. This complexity arose from modularization, which was necessary to support the wide range of products and platforms available in today&#39;s Apple ecosystem.</p>
<p>
To assist teams with challenges related to generated projects, we created <a href="https://github.com/tuist/XcodeGraph">XcodeGraph</a>, a data structure that standardizes the representation of Xcode projects and workspaces. This enabled us to extend some of our solutions—such as our graph visualization tool and selective testing—from generated projects to any Xcode project.</p>
<p>
We knew it would be a powerful tool, but its potential exceeded our expectations. With the emergence of LLM-based technologies and, more recently, the <a href="https://modelcontextprotocol.io/introduction">MCP</a> protocol standardized by Claude—which <a href="https://nshipster.com/authors/mattt/">Mattt</a> <a href="https://nshipster.com/model-context-protocol/">discussed</a> on his popular blog <a href="https://nshipster.com/model-context-protocol/">NSHipster</a>—we couldn’t help but wonder: Could we leverage MCP to transform developers’ LLM-based chat apps and code editors, like Cursor, into Xcode project experts capable of answering questions that would otherwise be difficult or impossible? The answer is yes.</p>
<p>
In this blog post, I’m excited to announce a new CLI feature: the Tuist MCP server, which allows you to chat with your Xcode projects and workspaces.</p>
<h2 id="what-is-mcp?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is MCP?<a href="#what-is-mcp?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is MCP?"></a></h2>
<p>
MCP is a protocol proposed by <a href="https://claude.ai/">Claude</a> that enables LLMs to interface with the outside world. Editors like <a href="https://www.cursor.com/">Cursor</a> or <a href="https://zed.dev/">Zed</a>, as well as chat apps like <a href="https://claude.ai/">Claude</a>—acting as <strong>clients</strong>—can interact with MCP servers using various transport protocols, including standard input. In simpler terms, a client can spawn a process and communicate with the server through its standard input pipeline.</p>
<p>
The server can provide <a href="https://modelcontextprotocol.io/docs/concepts/resources">resources</a>, <a href="https://modelcontextprotocol.io/docs/concepts/prompts">prompts</a>, and <a href="https://modelcontextprotocol.io/docs/concepts/tools">tools</a> to respond to actions (e.g., building an app). It can even enable more agentic behaviors by allowing the server to interact with the model via <a href="https://modelcontextprotocol.io/docs/concepts/sampling">sampling</a>.</p>
<p>
This might sound abstract, so let’s make it practical. LLMs lack knowledge of your specific development environment, including your projects, but they do understand Xcode projects and workspaces in general. What if you could let them &quot;see&quot; your projects and workspaces? That’s where resources come in. Tuist can transform your Xcode projects and workspaces into a serializable graph and share it with the LLM, allowing you to tap into its expertise to better understand your projects.</p>
<p>
Still sounding abstract? Let’s explore a concrete example together.</p>
<h2 id="setting-up-your-environment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Setting up your environment<a href="#setting-up-your-environment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Setting up your environment"></a></h2>
<p>
Install the latest version of Tuist and run any of the following commands to configure either Claude to connect to the Tuist MCP server:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist mcp setup claude    </shiki-highlight>
  </div>
</div>
<p>
For any other clients that support the Model Context Protocol protocol, you can configure them using the <code class="inline">tuist mcp</code> command with standard input as the transport protocol. The Tuist MCP will list projects you’ve recently interacted with as resources. Select the one you want to use to provide context, and then try asking questions like:</p>
<ul>
  <li>
What are the direct and transitive dependencies of a specific target?  </li>
  <li>
Which target has the most source files, and how many does it include?  </li>
  <li>
What are all the static products (e.g., static libraries or frameworks) in the graph?  </li>
  <li>
Can you list all targets, sorted alphabetically, along with their names and product types (e.g., app, framework, unit test)?  </li>
  <li>
Which targets depend on a particular framework or external dependency?  </li>
  <li>
What’s the total number of source files across all targets in the project?  </li>
  <li>
Are there any circular dependencies between targets, and if so, where?  </li>
  <li>
Which targets use a specific resource (e.g., an image or plist file)?  </li>
  <li>
What’s the deepest dependency chain in the graph, and which targets are involved?  </li>
  <li>
Can you show me all the test targets and their associated app or framework targets?  </li>
  <li>
Which targets have the longest build times based on recent interactions?  </li>
  <li>
What are the differences in dependencies between two specific targets?  </li>
  <li>
Are there any unused source files or resources in the project?  </li>
  <li>
Which targets share common dependencies, and what are they?  </li>
</ul>
<p>
You can watch the video in action here:</p>
<iframe title="Transform your LLM into an Xcode project copilot" width="560" height="315" src="https://videos.tuist.dev/videos/embed/hnwUYxkbaeLn3WjZSc533s" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="closing-thoughts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing thoughts<a href="#closing-thoughts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing thoughts"></a></h2>
<p>
Languages as an interface to technology are not only here to stay but are poised to redefine how we interact with the digital world—and we’re only beginning to unlock their vast potential. At Tuist, we’re excited to empower you to bridge this emerging landscape with your projects and development environment. Our commitment is to keep you in full control, ensuring you decide precisely what data you share and with whom.</p>
<p>
Exposing the graph of your most recently accessed projects is just the first step in this journey. Looking ahead, we plan to expand the scope of available information, incorporating details automatically gathered by the server from your build and test runs, as well as the resulting artifacts. As always, our mission is to handle the heavy lifting behind the scenes, freeing you to concentrate on what truly matters: crafting exceptional applications with greater speed and efficiency.</p>
<p>
If this piques your interest, we invite you to explore <a href="https://github.com/tuist/tuist/pull/7366">our implementation</a> and consider contributing new resources or tools to the server. Your input can help us enhance the features we deliver to the Tuist community. Additionally, we’ve created a dedicated repository, <a href="https://github.com/tuist/awesome-swift-mcp">awesome-swift-mcp</a>, with other valuable MCP-related resources in the context of development with Swift.</p>
<p>
Stay tuned for more exciting developments from the Tuist team as we continue to push the boundaries of MCP awesomeness. We’re eager to see how you’ll harness these tools to shape the future of app development!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Optimize your Swift test suite to run faster ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Slow test suites drag your team down. Learn how to speed up your Swift tests effectively. ]]></summary>
      <link href="https://tuist.dev/blog/2025/03/25/tests"/>
      <id>https://tuist.dev/blog/2025/03/25/tests</id>
      <updated>Tue, 25 Mar 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When projects kick off and establish their workflows, developers typically define processes that can run either locally or in a Continuous Integration (CI) environment. The common mental model is to interact with the project as a whole—for instance, by building the entire codebase or running the full test suite. This approach works seamlessly for small projects, but as the project scales with more modules, developers, and teams, it can turn into a productivity bottleneck.</p>
<p>
Sooner or later, action becomes necessary—especially if you aim to maximize your CI and engineering resources, safeguard your team&#39;s <a href="/blog/2025/02/28/momentum">building momentum</a>, and keep pace with business demands. In this post, we’ll explore key areas where optimizations can be implemented, along with potential challenges that may emerge when accelerating your test suite. Let’s dive in.</p>
<h2 id="run-tests-in-parallel" tabindex="-1" class="marketing__blog_post__body__content__heading">
Run tests in parallel<a href="#run-tests-in-parallel" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Run tests in parallel"></a></h2>
<p>
Modern hardware, such as Apple Silicon-powered laptops and CI environments, boasts multiple cores, enabling true parallelism—running multiple tasks simultaneously. While parallelism is a powerful tool, it’s not always necessary, as many applications are I/O-bound, meaning they spend time waiting for input/output operations to complete rather than taxing the CPU. In testing, for example, while one test awaits the completion of an asynchronous operation, the test runner can leverage shared resources to execute other tests concurrently.</p>
<p>
In Swift Testing, parallel execution is enabled by default. However, with XCTest, you may need to opt in via the test plan settings. If you’re using <code class="inline">xcodebuild</code>, you can control parallelization with these options:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
-parallel-testing-enabled YES|NO                         overrides the per-target setting in the scheme
-parallel-testing-worker-count NUMBER                    the exact number of test runners that will be spawned during parallel testing
-maximum-parallel-testing-workers NUMBER                 the maximum number of test runners that will be spawned during parallel testing    </shiki-highlight>
  </div>
</div>
<p>
One might assume parallelization is the ultimate solution for speeding up test execution. Yet, as soon as you enable it, new challenges surface that you may not have anticipated.</p>
<h3 id="environment-limitations" tabindex="-1" class="marketing__blog_post__body__content__heading">
Environment limitations<a href="#environment-limitations" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Environment limitations"></a></h3>
<p>
Parallelization has its limits. For instance, UI tests often rely on simulators, which are resource-intensive and can’t be spawned indefinitely. You might hit a ceiling where adding more parallel tasks yields diminishing returns due to hardware or system constraints.</p>
<h3 id="code-not-designed-for-parallel-access" tabindex="-1" class="marketing__blog_post__body__content__heading">
Code not designed for parallel access<a href="#code-not-designed-for-parallel-access" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Code not designed for parallel access"></a></h3>
<p>
Functional programming advocates for avoiding shared mutable state to ensure determinism—a principle that also facilitates parallelization by scoping state to individual functions. While Swift supports functional programming, shared mutable state often creeps in via static variables or singletons. When you increase parallelization, this global state can lead to two issues:</p>
<ul>
  <li>
<strong>Data Races:</strong> Multiple threads accessing the same memory simultaneously can cause crashes or undefined behavior during test execution.  </li>
  <li>
<strong>Race Conditions:</strong> Tests whose outcomes depend on execution order may become flaky, as detailed in resources like <a href="https://www.jetbrains.com/teamcity/ci-cd-guide/concepts/flaky-tests/">JetBrains&#39; guide on flaky tests</a>.  </li>
</ul>
<p>
To fully harness parallelization, you’ll likely need to refactor your code to eliminate shared state. This involves scoping state to each test and passing it explicitly to the logic under test. To avoid verbose dependency injection, consider libraries like <a href="https://github.com/pointfreeco/swift-dependencies">swift-dependencies</a> from Point-Free or Apple’s <a href="https://github.com/apple/swift-service-context">swift-service-context</a>. These tools allow each test to instantiate its dependencies, providing a clean API for runtime access.</p>
<p>
For data races, enabling <a href="https://www.swift.org/migration/documentation/swift-6-concurrency-migration-guide/completechecking">Complete Concurrency Checking</a> in Swift 6 is invaluable. While often touted for app stability, it’s equally critical for reliable parallel test execution, catching potential races at compile time.</p>
<h2 id="parallelization-across-environments" tabindex="-1" class="marketing__blog_post__body__content__heading">
Parallelization across environments<a href="#parallelization-across-environments" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Parallelization across environments"></a></h2>
<p>
When single-environment limits—like the number of available simulators—cap your parallelization, you can distribute tests across multiple CI environments. For example, if one environment supports only 4 simulators, adding a second environment doubles your capacity to 8.</p>
<p>
To achieve this, decouple building from testing. Use the <code class="inline">build-for-testing</code> option in <code class="inline">xcodebuild</code> to compile your scheme without running tests:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
xcodebuild \
    -workspace MyApp.xcworkspace \
    -scheme MyApp \
    -sdk iphonesimulator \
    -destination &#39;generic/platform=iOS&#39; \
    build-for-testing    </shiki-highlight>
  </div>
</div>
<p>
This generates an <code class="inline">.xctestrun</code> file in the default DerivedData directory (<code class="inline">~/Library/Developer/Xcode/DerivedData/</code>). This file bundles everything needed to run tests and must be transferred from the build environment to each test-running environment. To locate it, use:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
XCTEST_RUN_PATH=$(find ~/Library/Developer/Xcode/DerivedData/ -name &quot;*.xctestrun&quot;)    </shiki-highlight>
  </div>
</div>
<p>
In a CI system like GitHub Actions, cache the file with:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
- name: Cache .xctestrun
  id: xctestrun-cache
  uses: actions/cache/save@v4
  with:
    path: ~/Library/Developer/Xcode/DerivedData/**/*.xctestrun
    key: xctestrun-${{ github.run_id }}-${{ github.run_attempt }}    </shiki-highlight>
  </div>
</div>
<p>
Restore it in test environments with:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
- name: Restore .xctestrun
  uses: actions/cache/restore@v4
  with:
    key: xctestrun-${{ github.run_id }}-${{ github.run_attempt }}    </shiki-highlight>
  </div>
</div>
<p>
Then execute tests with <code class="inline">test-without-building</code>, specifying the .xctestrun file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
xcodebuild \
    -workspace MyApp.xcworkspace \
    -scheme MyApp \
    -sdk iphonesimulator \
    -destination &#39;generic/platform=iOS&#39; \
    -xctestrun $(find ~/Library/Developer/Xcode/DerivedData/ -name &quot;*.xctestrun&quot;) \
    -only-testing Tests1 \
    test-without-building    </shiki-highlight>
  </div>
</div>
<blockquote>
  <p>
Dynamic test splitting isn’t supported natively. Use test identifiers (e.g., test case names or targets) to group and distribute tests manually.  </p>
</blockquote>
<p>
To estimate total execution time, use this formula, assuming tests within each environment run fully in parallel:</p>
<p>
Total time = ( Total tests / ( Environment parallelization limit x Environments) ) x Average time per test</p>
<p>
For example, with 200 UI tests averaging 5 seconds each and a per-environment limit of 4 simulators:</p>
<ul>
  <li>
<strong>1 environment:</strong> Compilation time + 4.1 minutes  </li>
  <li>
<strong>2 environments:</strong> Compilation time + 2.08 minutes  </li>
  <li>
<strong>3 environments:</strong> Compilation time + 1.38 minutes  </li>
  <li>
<strong>4 environments:</strong> Compilation time + 1.04 minutes  </li>
</ul>
<h2 id="run-fewer-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
Run fewer tests<a href="#run-fewer-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Run fewer tests"></a></h2>
<p>
Running an entire test suite for every commit is not necessary. If you change a few lines of code in a pull request (PR), you should only run the tests that are directly or transitively connected to the change. The question is: how do you identify these tests?</p>
<p>
Solutions have emerged in this ecosystem and others to solve this problem, often referred to as selective test running. One such solution is <a href="https://github.com/mikeger/XcodeSelectiveTesting">XcodeSelectiveTesting</a> by <a href="https://github.com/mikeger">Mike Gerasymenko</a>, which uses the Git repository to determine changes in files and combines that information with the project&#39;s graph to identify the tests that need to run. By default, it compares against a baseline branch, but it can alternatively compare against a locally persisted changeset.</p>
<p>
We also <a href="https://docs.tuist.dev/en/guides/develop/selective-testing">provide a solution</a> that takes a different approach. Instead of relying on Git, we use fingerprinting to obtain a hash of the modules that have changed. We also handle persisting the information for you, ensuring that the incrementality of selective testing works across branches and commits, not just from a branch and the base reference. You can use it with <a href="https://docs.tuist.dev/en/guides/develop/projects">generated projects</a> as well as standard Xcode projects.</p>
<h2 id="speed-up-compilation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Speed up compilation<a href="#speed-up-compilation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Speed up compilation"></a></h2>
<p>
Before tests can run, the code must be compiled—a costly step in clean CI environments. Optimize this with build systems like <a href="https://bazel.build/">Bazel</a> or <a href="https://docs.tuist.dev/en/guides/develop/cache">Tuist Cache</a>, which cache build artifacts to skip redundant compilation in clean builds.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
Rapid feedback on pull requests empowers developers to iterate quickly and meet business goals. While multitasking during long CI runs is an option, it often hampers focus and productivity. The closer you get to instant feedback, the better your team can perform.</p>
<p>
If your CI pipelines haven’t been revisited since their inception, it’s time to invest in optimization. Your team, business, and customers will reap the rewards of faster, more efficient workflows.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Strategies to avoid merge conflicts in Xcode Projects ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn why Xcode’s project.pbxproj triggers Git conflicts and how solutions like workspaces, SwiftPM or buildable groups can help developers reduce frustration in collaborative projects. ]]></summary>
      <link href="https://tuist.dev/blog/2025/03/21/git-conflicts"/>
      <id>https://tuist.dev/blog/2025/03/21/git-conflicts</id>
      <updated>Fri, 21 Mar 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
If you’ve collaborated with other developers on an Xcode project, you’ve likely encountered frequent Git conflicts—more so than in any other development ecosystem. This can be incredibly frustrating, especially if you’re unfamiliar with the <code class="inline">project.pbxproj</code> file, where these conflicts typically arise. </p>
<p>
In this post, we’ll explore why these conflicts occur in Xcode projects, examine the various solutions that have emerged to address them, and provide actionable steps you can take to eliminate this common source of frustration for developers.</p>
<h2 id="why-do-conflicts-exist?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why do conflicts exist?<a href="#why-do-conflicts-exist?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why do conflicts exist?"></a></h2>
<p>
Xcode projects are a directory with the extension <code class="inline">.xcodeproj</code> that contain a file <code class="inline">project.pbxproj</code>.
Back when Apple introduced Xcode in 2023 as part of Mac OS X 10.3,
projects were small, 
and collaboration following trunk-based development was not that common as it is today.
For context,
Linus Torvalds released Git in 2005,
and GitHub was founded in 2008.
So at the time, conflicts did not exist,
and Apple decided to create a monolithic file where all the project description would be stored, <code class="inline">project.pbxproj</code>.
The <code class="inline">project.pbxproj</code> is a property list file that was not designed to be edited directly.
Instead, the changes are done using Xcode&#39;s UI, and Xcode is the one responsible for translating those changes into the <code class="inline">project.pbxproj</code> file.
Group and file references (for example, to reference Swift files) are among the building blocks
that represent the hierarchical structure of the project. For example:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
/* Begin PBXFileReference section */
        6CA84C022D8DAA1200086F24 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
        6CA84C0A2D8DAA1200086F24 /* FrameworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FrameworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */    </shiki-highlight>
  </div>
</div>
<p>
These lines update whenever a file is added, removed, or relocated in the project hierarchy—common actions in a pull request (PR). This frequent updating is a primary driver of merge conflicts.</p>
<p>
To address this, Apple introduced workspaces in <a href="https://developer.apple.com/xcode/">Xcode 4</a> in 2011, enabling teams to split targets across multiple projects. The idea was that distributing <code class="inline">project.pbxproj</code> files across smaller projects would reduce conflicts. While no hard data confirms their adoption rate, workspaces likely didn’t gain the traction Apple anticipated.</p>
<p>
In September 2016, with the release of <a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-8-release-notes">Xcode 8</a>, Apple added comments to project.pbxproj files (e.g., <code class="inline">/* Framework.framework */</code>). This made conflicts easier to resolve by providing context, compared to cryptic identifiers like <code class="inline">6CA84C022D8DAA1200086F24</code>. Yet, in 2025, teams still grapple with these issues—not because solutions are lacking, but because awareness or implementation lags.</p>
<p>
Let’s dive into practical strategies to mitigate these conflicts.</p>
<h2 id="splitting-a-monolith-into-multiple-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Splitting a monolith into multiple projects<a href="#splitting-a-monolith-into-multiple-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Splitting a monolith into multiple projects"></a></h2>
<p>
Since 2011, one effective approach has been organizing your workspace into multiple projects. For instance, you could create a project per domain or feature, each containing its source files, tests, and a demo app. Check out <a href="https://docs.tuist.io/guides/develop/projects/tma-architecture">Tuist’s modular architecture</a> guide for inspiration on structuring your projects efficiently.</p>
<p>
While this reduces conflicts by distributing the dependency graph, it may slightly increase Xcode’s indexing and build times due to the added complexity of resolving inter-project dependencies. You’ll also need to explicitly define these dependencies to ensure Xcode’s build system links products correctly.</p>
<h2 id="project-generation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project generation<a href="#project-generation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project generation"></a></h2>
<p>
Tools like <a href="https://docs.tuist.dev">Tuist</a> and <a href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a> (<a href="https://careersatdoordash.com/blog/how-doordash-uses-xcodegen-to-eliminate-project-merge-conflicts/">How DoorDash uses XcodeGen to eliminate project merge conflicts</a>) offer an alternative by introducing domain-specific languages (DSLs) in Swift or YAML to define projects. Instead of listing every file (e.g., one per line), they use wildcard patterns like <code class="inline">/Sources/**/*.swift</code>, reducing the file’s churn and thus the likelihood of conflicts.</p>
<p>
The popularity of project generation stems from this pain point. Tuist, for example, not only minimizes conflicts but also simplifies modularization and optimizes workflows. If conflicts are your only gripe, project generation might be overkill. But if modularization complexity or slow workflows also frustrate you, tools like Tuist are worth exploring.</p>
<h2 id="using-swiftpm-as-a-project-manager" tabindex="-1" class="marketing__blog_post__body__content__heading">
Using SwiftPM as a project manager<a href="#using-swiftpm-as-a-project-manager" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Using SwiftPM as a project manager"></a></h2>
<p>
In 2015, Apple introduced the <a href="https://www.swift.org/package-manager/">Swift Package Manager (SwiftPM)</a>, initially a dependency management tool. By September 2016, with its integration into Xcode, developers began using it to link local and external dependencies. What started as a dependency manager evolved into a de facto project manager for many.</p>
<p>
Frustrated by <code class="inline">project.pbxproj</code> conflicts and modularization woes, developers migrated their project graphs to SwiftPM. Like project generation, SwiftPM uses wildcard patterns (e.g., <code class="inline">Sources/**/*.swift</code>), lowering conflict risks. However, this shift trades one annoyance for another: Xcode can become sluggish, with tiny graph changes triggering slow, asynchronous processes—or worse, leaving your project in an inconsistent state requiring a clean of derived data.</p>
<h2 id="synchronized-groups-(buildable-folders)-in-xcode-16" tabindex="-1" class="marketing__blog_post__body__content__heading">
Synchronized groups (buildable folders) in Xcode 16<a href="#synchronized-groups-(buildable-folders)-in-xcode-16" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Synchronized groups (buildable folders) in Xcode 16"></a></h2>
<p>
In 2024, Apple introduced synchronized groups in <a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes">Xcode 16</a>, akin to wildcard functionality. These groups reference a directory, and Xcode syncs all files within it, allowing exceptions (e.g., excluding a file or tweaking configurations).</p>
<p>
In Xcode, these are called “folders.” To convert a group, right-click it and select “Convert to Folder”:</p>
<img alt="An image that shows the right click menu on a group with the option to convert to folder" width="400" src="/marketing/images/blog/2025/03/21/convert-to-folder.jpeg">
<p>
Before converting, use a tool like <a href="https://github.com/qonto/XcodeGroupSync">XcodeGroupSync</a> to align your groups with the file system. Skipping this step risks compilation or runtime errors from missing files or misconfigurations. This feature is a low-effort, high-return investment for teams.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
Source control merge conflicts in Xcode projects, driven by the project file, have plagued developers for years. Fortunately, you have multiple options to tackle them: splitting projects, adopting project generation tools like Tuist or XcodeGen, leveraging SwiftPM, or using synchronized groups in Xcode 16. Each solution has trade-offs, but they all aim to streamline collaboration and reduce frustration.</p>
<p>
Start small—experiment with synchronized groups or a multi-project workspace—and scale up based on your team’s needs. By addressing this pain point, you’ll boost productivity and make your development process smoother. Have a favorite solution? Share it with us on <a href="https://fosstodon.org/@tuist">Mastodon</a>!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Own your Swift apps' automation ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Discover how to increase flexibility in your CI workflow for Swift apps by taking ownership of your automation and reducing provider dependencies. ]]></summary>
      <link href="https://tuist.dev/blog/2025/03/11/own-your-automation"/>
      <id>https://tuist.dev/blog/2025/03/11/own-your-automation</id>
      <updated>Tue, 11 Mar 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Technology evolves very rapidly these days.
This is great, because there&#39;s more innovation and more opportunities.
However,
it also means non-crowded markets filled with innovation eventually become crowded and stagnate.
What used to be your economic moat is now a commodity.
And what used to be your competitive advantage is now an expected baseline.</p>
<p>
Since a business&#39;s ultimate goal is to grow and stay relevant,
they need to adapt accordingly.
Some design their business environment to foster innovation.
This becomes more challenging as the company grows,
and is in fact what makes <a href="https://pepicrft.me/blog/2025/03/04/tuist-mental-models">open source companies</a> outcompete their closed-source counterparts.
Other companies focus on building ecosystems where more players are incentivized to keep their business relevant.
I&#39;d say it&#39;s the proprietary version of the open-source ethos.
If you think of Apple&#39;s app store, that&#39;s what it is.
And last but not least, some companies invest in creating seamless experiences that increase customer retention.
The integrated nature of their solutions provides such value that customers choose to stay.</p>
<h2 id="continuous-integration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Continuous integration<a href="#continuous-integration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Continuous integration"></a></h2>
<p>
What does all of this have to do with Swift apps&#39; automation? A lot more than you might think.
Last year, while chatting with an app developer,
he shared that they were renovating their contract with their CI provider,
that the price had increased significantly,
and that there was a company that even offered to take care of migrating their pipelines.
I was surprised by this situation in CI,
especially considering there are many choices these days to choose from.
What opportunities might we be missing as an ecosystem?</p>
<p>
This brings me to an interesting dilemma, which you can apply to many aspects of life, and is closely related to how services evolve over time, sometimes prioritizing profit over values.
If you find yourself in a position where a service price increases substantially, and you feel constrained in your options,
should it be your responsibility to maintain flexibility,
or should that be the responsibility of the service provider?
Ideally both parties would work together on this, but in today&#39;s world, maintaining your own flexibility is valuable.</p>
<p>
We&#39;ve reached this position partly because we&#39;ve often entrusted CI providers with full ownership of our automation.
It&#39;s completely understandable.
When you&#39;re reading docs on how to set up a CI pipeline,
you don&#39;t have time to think deeply about the long-term implications of choices made based on those suggestions,
but some of them implicitly create strong dependencies on the service provider,
which can eventually limit your options.</p>
<p>
In this post, I&#39;d like to share why taking more ownership of your automation might be beneficial in today&#39;s CI landscape,
where dependencies naturally form and what you can do about it with today&#39;s tools, and share a bit about our approach to CI and our future plans.</p>
<h2 id="why-owning-your-automation-is-a-good-idea" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why owning your automation is a good idea<a href="#why-owning-your-automation-is-a-good-idea" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why owning your automation is a good idea"></a></h2>
<p>
There are several benefits to owning more of your automation:</p>
<ul>
  <li>
<strong>Portability:</strong> In a world with many options, it&#39;s valuable to maintain flexibility to move between providers if needed (e.g., when your needs or circumstances change).  </li>
  <li>
<strong>Debuggability:</strong> If you own your automation, you can debug it easily because your automation is environment agnostic. You can run it locally or in any CI provider. At the end of the day, those should just be macOS environments with the development tools installed.  </li>
  <li>
<strong>Flexibility:</strong> When relying heavily on specific CI providers, you&#39;re constrained by the DSL of their pipelines and their capabilities. Many choose YAML as a format, which isn&#39;t always the most expressive language for complex automation needs.  </li>
</ul>
<p>
Moreover, Git platforms like <a href="https://github.com">GitHub</a>, <a href="https://gitlab.com">GitLab</a>, and <a href="https://codeberg.org">Codeberg</a> have incorporated CI capabilities where you can bring your remote build environments with services like <a href="https://cirrus-runners.app/">Cirrus Runners</a> and <a href="https://depot.dev/">Depot</a>. Thanks to that, you have a CI experience that&#39;s more tightly integrated with the platform where developers are already spending their time.</p>
<p>
The provisioning of <a href="/blog/2025/02/12/vm">macOS build environments</a> might get commoditized too by cloud providers like AWS, so at that point you might be able to just add your AWS credentials to your Git platform and voilà.</p>
<p>
Because the space is changing rapidly, especially with projects like <a href="https://dagger.io/">Dagger</a>, we think the time is perfect to start thinking about taking greater ownership of your automation. Let&#39;s talk about pipelines first.</p>
<h2 id="ci-pipelines" tabindex="-1" class="marketing__blog_post__body__content__heading">
CI pipelines<a href="#ci-pipelines" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to CI pipelines"></a></h2>
<p>
When you think about the capabilities of a CI provider and how they&#39;re reflected in your pipelines, we can group the steps into the following categories:</p>
<ol>
  <li>
<strong>Installing environment tools:</strong> Like <code class="inline">Fastlane</code>, <code class="inline">swiftlint</code>, or <code class="inline">tuist</code>. In many cases, you find steps that run <code class="inline">brew install</code>, and in other cases, you use steps from the provider, like with GitHub Actions where you have <code class="inline">actions/setup-xxx</code> steps that encapsulate the installation of tools.  </li>
  <li>
<strong>Caching needs:</strong> Pipelines also allow declaring cacheable directories along with the logic for calculating a hash to store and restore them.  </li>
  <li>
<strong>Core action:</strong> Every job usually has a core action, that&#39;s either a call to the language toolchain (e.g. <code class="inline">swift test</code>) or to some script that extends the underlying command with some pre and post logic and defaults. In the context of Swift app development, it&#39;s common to find invocations to Fastlane lanes, <code class="inline">bundle exec fastlane build</code>.  </li>
  <li>
<strong>Exposing secrets:</strong> That are configured through their UI, exposed as environment variables to the pipeline, and filtered out from the logs.  </li>
  <li>
<strong>Job composition:</strong> Then there are some pipeline primitives to combine jobs (e.g. run this one after that other one completes, or run these two things in parallel). This is an area where some companies have invested more than others, for example by providing a visual editor for the pipeline.  </li>
</ol>
<p>
Let&#39;s talk about how you can take more ownership of each aspect.</p>
<h2 id="installing-tools" tabindex="-1" class="marketing__blog_post__body__content__heading">
Installing tools<a href="#installing-tools" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Installing tools"></a></h2>
<p>
It&#39;s common to see repositories having an <code class="inline">install.sh</code> script, or steps in the README.md that developers can execute or follow to install the tools. In some cases, the same script is run on CI, and in other cases, they use community steps that come with caching capabilities built-in.
As we covered in <a href="/blog/2025/02/04/mise">this post</a>, this is something that you can solve with Mise, and have a unified solution that works across environments (local and CI). All you need is a <code class="inline">mise.toml</code> file with the tools your project depends on:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[tool]
swiftformat = &quot;0.55.5&quot;
ruby =  &quot;3.4.2&quot;

[hooks]
postinstall = &quot;bundle install&quot;    </shiki-highlight>
  </div>
</div>
<p>
So all you need in your pipelines and in your local environment is a <code class="inline">mise install</code> command. Simple, isn&#39;t it?
Mise also supports installing any SwiftPM package that&#39;s publicly available in a repository by using the convention:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
&quot;spm:account/repo&quot; = &quot;1.2.3&quot;    </shiki-highlight>
  </div>
</div>
<p>
And even install tools written in other programming languages by pulling the binaries using <a href="https://github.com/houseabsolute/ubi">UBI</a> or letting Mise compile them from the source, for example Go or Rust CLIs.</p>
<p>
A side advantage of adopting Mise is that you minimize issues related to inconsistent versions, and you can adopt tools written in other languages or that run in other runtimes, like Fastlane and Ruby, without worrying too much about whether developers will be able to provision their environment successfully. That&#39;s all delegated to Mise.</p>
<p>
Mise all the things!</p>
<h2 id="caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
Caching<a href="#caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Caching"></a></h2>
<p>
This is one of the more challenging aspects.
Not because it&#39;s impossible to solve, since you could use a CLI to store and restore artifacts using an S3-compliant storage,
but because the process would be quite involved and you&#39;d need to build your own hashing function.</p>
<p>
We started working on addressing this with <a href="https://github.com/tuist/cache">cache</a>, a tool that brings declarative caching capabilities to any scripts.
We are drawing inspiration from <a href="https://usage.jdx.dev/">usage</a> regarding the design.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env cache bash
# CACHE paths [&quot;.build&quot;]
# CACHE key &quot;..&quot;
# CACHE restore_keys [...]    </shiki-highlight>
  </div>
</div>
<h2 id="action" tabindex="-1" class="marketing__blog_post__body__content__heading">
Action<a href="#action" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Action"></a></h2>
<p>
This is an area the Swift ecosystem solved a long time ago with <a href="https://github.com/fastlane/fastlane">Fastlane</a>,
and it&#39;s something that many organizations use today.
Fastlane provides sensible defaults to the underlying tooling, 
and has its own system for encapsulating and distributing shareable units of automation called lanes through Ruby gems.</p>
<p>
Since Fastlane was created and popularized, a lot has changed,
and we&#39;re starting to notice evolving preferences.
Apple&#39;s toolchain has gotten better and more capable.
We have LLMs that facilitate writing in languages like Bash, making scripts more portable without requiring a Ruby runtime.
Note that by moving to something like Bash,
you&#39;d trade having access to an ecosystem of steps,
but Bash has a registry too, <a href="https://www.basher.it/">Basher</a>,
and with LLM-based code editors being able to write most of your automation code these days,
the need for sharing or accessing shared steps is not as pressing as it used to be.</p>
<p>
At Tuist, all our scripts are bash. Once written, we barely touch them. You can model them as <a href="https://mise.jdx.dev/tasks/">Mise tasks</a> and use comments in the script to declare the CLI interface:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env bash
#MISE description=&quot;Build MyApp&quot;
#MISE alias=&quot;b&quot;
#USAGE flag &quot;-n --no-signing&quot; help=&quot;Disable the signing&quot;

if [ &quot;$usage_no_signing&quot; = &quot;true&quot; ]; then
  xcodebuild -scheme MyApp -workspace $MISE_PROJECT_ROOT/MyApp.xcworkspace clean build CODE_SIGN_IDENTITY=&quot;&quot; CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
else
  xcodebuild -scheme MyApp -workspace $MISE_PROJECT_ROOT/MyApp.xcworkspace clean build
fi    </shiki-highlight>
  </div>
</div>
<h2 id="secrets" tabindex="-1" class="marketing__blog_post__body__content__heading">
Secrets<a href="#secrets" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Secrets"></a></h2>
<p>
Another capability of CI providers,
one that in fact makes debugging pipelines harder,
is exposing secrets and redacting them from the logs.</p>
<p>
The former is something that Mise solves with their <a href="https://mise.jdx.dev/environments/secrets.html">secrets</a> capability.
So your secrets can be part of your repository, but they&#39;re encrypted using a pair of public and private keys.
This offers advantages over managing through your CI provider&#39;s UI, some of which don&#39;t have a record of the changes that happened in the past and the reasons that motivated them. With Mise&#39;s approach, that information is in the repo.</p>
<p>
You can have one or multiple <code class="inline">.env.json</code> files, each representing an environment, and they are encrypted, so only the person (or the environment) with the private key can decrypt them.</p>
<p>
Note that you&#39;ll need to be careful not to print their values through standard output. CI services redact the output, but by shifting secrets to your repo, that becomes your responsibility. This is something we (or Mise) might build tooling for in the future.</p>
<h2 id="job-composition" tabindex="-1" class="marketing__blog_post__body__content__heading">
Job composition<a href="#job-composition" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Job composition"></a></h2>
<p>
Pipelines typically do things like run x and y in parallel, or on failure of x, run y. On top of this ability, CI providers build features like UI that allows you to visualize the concurrency and the timeline of the execution.</p>
<p>
Note that concurrency is something that you can achieve within a single action. Most of the work that you&#39;ll do from there are IO-bound operations, like interacting with the network, or running a system process, and all runtimes provide a way to spawn multiple processes and wait for them to finish. In the context of Swift, this would be creating a task group and adding tasks to it.</p>
<p>
Note that by doing that, we&#39;re making different tradeoffs:</p>
<ol>
  <li>
The ability to retry individual steps.  </li>
  <li>
The ability to visualize the pipeline execution.  </li>
  <li>
The ability to work around concurrency limitations of underlying tools (e.g. number of simulators running)  </li>
</ol>
<p>
We believe all of these challenges are solvable while maintaining flexibility, as <a href="https://dagger.io/">Dagger</a> is demonstrating, but exploring them in the context of app development is an opportunity that&#39;s still open.</p>
<h2 id="what's-next?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next?<a href="#what's-next?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next?"></a></h2>
<p>
As you might have noticed, there are already many things you can do to increase your flexibility when working with CI providers, ensuring you can choose solutions that best fit your needs. While we&#39;re not yet at the ideal state in terms of tooling to maximize this flexibility, this is where we&#39;d like Tuist to help. In the following months we&#39;ll explore:</p>
<ul>
  <li>
Bringing the declaration of caching needs closer to scripts and offering it as an open source commons that&#39;s platform and language agnostic.  </li>
  <li>
Building another open source tool and toolkit to redact secrets, and maybe hooking Mise into it to use it as a backend.  </li>
  <li>
Drawing inspiration from Dagger, and exploring what a Swift-based DSL that&#39;s CI-platform independent would look like. Unlike them, we won&#39;t virtualize using Docker, because for Swift apps, we need a macOS environment. We&#39;ll apply many of the learnings from building the generated projects&#39; DSL. We&#39;ll use the toolchains for redacting the secrets and caching.  </li>
  <li>
Exploring alternative ways to enhance job composition. This is an area we&#39;re still exploring, so stay tuned.  </li>
  <li>
Also drawing inspiration from Dagger, we&#39;ll investigate if we can build a CLI-first experience for CI, where you can do things like piping logs to your terminal.  </li>
</ul>
<p>
We strongly believe everyone should have the freedom to choose the CI provider that aligns with their values and needs, and we&#39;re excited to contribute tools that enhance this flexibility for developers.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Momentum ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Protect your developers' momentum to build better apps. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/28/momentum"/>
      <id>https://tuist.dev/blog/2025/02/28/momentum</id>
      <updated>Fri, 28 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Engineering resources are one of the most costly assets in any tech organization, hence the many conversations around AI taking their jobs or helping make more effective use of them. It&#39;s common to see organizations forming teams with names like &quot;platform&quot; or &quot;core,&quot; which are responsible for ensuring teams closer to product are productive by providing them with optimized tools and workflows. Those teams are a human-powered &quot;copilot&quot; and can have a significant impact in meeting the needs of the organization. If you&#39;ve tried to assemble IKEA furniture with a professional screwdriver as opposed to the provided tools, you&#39;ll likely know how much different and more productive the experience is.</p>
<h2 id="productivity-goes-beyond-efficiency" tabindex="-1" class="marketing__blog_post__body__content__heading">
Productivity goes beyond efficiency<a href="#productivity-goes-beyond-efficiency" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Productivity goes beyond efficiency"></a></h2>
<p>
When we think of productivity, we tend to think of achieving something in less time. However, in creative jobs such as software crafting, when someone doesn&#39;t feel slowed down by the tools they use, they are also inspired to explore new ideas, which transitively benefit the business. In other words, unproductive environments are poor grounds for innovation.</p>
<p>
<strong>Developers&#39; momentum is crucial</strong></p>
<p>
This is why we are so interested in productivity in the app development space—it&#39;s the way to impact the quality of the apps that organizations put out there.</p>
<p>
But staying productive while building for Apple platforms is a challenge. When an app is small—one or two targets, a few dependencies, one product, and one platform to support—it&#39;s all fine. But how realistic is that? Very unrealistic. Sooner than later, momentum blockers knock at your door:</p>
<ul>
  <li>
A new dependency that comes with a Swift macro significantly increasing your compilation times.  </li>
  <li>
Recurrent random compilation errors that only go away once you clean derived data and waste your time in a clean build.  </li>
  <li>
One-liner PRs that need more than half an hour to get CI feedback.  </li>
  <li>
Tests unrelated to your changes causing your PR CI to fail, forcing you to retry and wait for another half an hour.  </li>
</ul>
<p>
The manifestation of all this is usually teams unable to match the speed of other platforms (e.g., web), leadership being extremely concerned about it, and radical decisions like adopting <a href="https://reactnative.dev">React Native</a> or swapping the build system with something like <a href="https://bazel.build">Bazel</a>. Other times, if organizations can afford it, they throw more engineering resources at the problem, as if productivity were only directly correlated to the number of engineers. It&#39;s way more complex than that.</p>
<p>
At Tuist, we love this domain. And the fact that Apple is not focused on this space makes app development productivity a sweet spot. I&#39;m not writing this post to sell you Tuist, which of course I&#39;d be happy if you do; I simply want to create awareness around the importance of protecting developers&#39; momentum and what some common momentum drains are in app development.</p>
<p>
In the following sections, I&#39;ll walk you through the most common momentum obstacles that we&#39;ve seen in organizations:</p>
<h2 id="1.-multi-repos" tabindex="-1" class="marketing__blog_post__body__content__heading">
1. Multi-repos<a href="#1.-multi-repos" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 1. Multi-repos"></a></h2>
<p>
We&#39;ve seen organizations, especially those with different products (i.e., multiple apps), scattering their targets across repositories. This comes with a versioning scheme and reliance on developers to follow it strictly (we are humans, we make mistakes). Changes are no longer atomic and span across repositories, releases need to be coordinated, and configuration needs to be made consistent through yet more tooling and processes (or alternatively, configuration becomes inconsistent across repos). Unless you have a strong need to share a piece of logic with other repositories or as an open source project, going down this path is a terrible idea. You&#39;d be surprised to see how common this is in our industry.</p>
<p>
What&#39;s the alternative? Monorepos. But monorepos make some classic assumptions and models fall apart. One of them is the idea that every commit should integrate everything in CI. That works fine if your monorepo is small, but if you change one line in app Foo, you don&#39;t want to be compiling app Bar in CI. This requires some investment on your end to be selective about what happens in CI, and this is something that Tuist helps you with. We selectively build and test based on the changes and try to optimize the process by reusing binaries across builds. This is what can make your 1-hour CI pipeline go down to minutes. Alternatively, you can make the investment yourself and leverage Git forge features like <a href="https://docs.github.com/en/repositories/managing-your-repositories-settings-and-features/customizing-your-repository/about-code-owners">CODEOWNERS</a> to improve the experience of working with monorepos, but I assure you it&#39;s worth the investment. Much better than having changes scattered across many repositories.</p>
<h2 id="2.-slow-feedback-loops" tabindex="-1" class="marketing__blog_post__body__content__heading">
2. Slow feedback loops<a href="#2.-slow-feedback-loops" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2. Slow feedback loops"></a></h2>
<p>
When you change something, you want to see it instantly. This instant feedback loop is what keeps your ideas energized and what makes you stay hours building new ideas into your apps. Sadly, this instant feedback loop gets easily disrupted by the Apple toolchain:</p>
<ul>
  <li>
A cryptic error in Xcode  </li>
  <li>
A failing LLDB  </li>
  <li>
A failing SwiftUI preview  </li>
  <li>
A slow compilation  </li>
</ul>
<p>
We&#39;ve normalized all the above, but that&#39;s too bad if you ask me. We need to fight back and be more critical about how terrible this is for the ecosystem. There&#39;s some work on Apple&#39;s side to tackle this by making things more explicit and bringing capabilities of modern build systems into Xcode&#39;s, but things move slower than what the ecosystem really needs. Resources are scarce, and issues continue to pile up. A new version of Xcode comes out fixing one issue but introduces a regression somewhere else. Everything seems to be moving faster and more reliably outside of Xcode.</p>
<p>
What does it take to improve the feedback and ensure things work more reliably? Embrace explicitness and consistency in your projects. Refrain from adding compile-time complexity, for example through script build phases, Swift Macros, or embeddable frameworks. The simpler and more explicit the compilation graph, the better for the reliability and performance of Xcode&#39;s build system, debugging tools, and editor. One thing that we don&#39;t cease to repeat is that the existence of a feature in Xcode doesn&#39;t mean it&#39;s the most suitable option at scale. For instance, while Swift Macros are cool, we&#39;d use them sparingly. Or build scripts are something we try to avoid.</p>
<p>
Hopefully with the above, developers will have to clean derived data less frequently (yay!). And if you still want a boost of performance in your feedback loop, you might consider something like Tuist binary caching and selective testing, which works with vanilla projects.</p>
<h2 id="3.-friction-while-previewing" tabindex="-1" class="marketing__blog_post__body__content__heading">
3. Friction while previewing<a href="#3.-friction-while-previewing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 3. Friction while previewing"></a></h2>
<p>
You&#39;ve built a new feature or just fixed something, and you want to share that with the rest of the team, your leads, or the product designers who designed the feature in the first place? In the web ecosystem, you&#39;d get a preview in seconds and share a link with your team that they can add feedback to. The frictionless nature of the process is an invitation to other people to participate in the feedback loop and help you shape the best work you can.</p>
<p>
The same is not true when developing apps for Apple platforms. Sharing the app from the PR? Unthinkable. Building it locally if I&#39;m a developer reviewing the PR? Too slow. The result? Trusting CI on their checks and reviewing the architecture of the code. But if the latter is something AI is going to be very good at, and there are signs of that because GitHub just announced that Copilot can be a reviewer too, how can humans support there? By manually testing the app:</p>
<ul>
  <li>
It feels slow  </li>
  <li>
It looks off on my iPhone 16  </li>
  <li>
The animation has too much delay  </li>
</ul>
<p>
We need to match the web there. But we have nightly builds, Pedro... Nightly builds are terrible for this. Once the nightly build is created, you&#39;ve lost the context of what has gone into it. If you have feedback, suddenly you have a new problem that you didn&#39;t have before—figuring out what introduced the bug that you are seeing, who authored that PR, and communicating what you saw with that person. Do you notice? It&#39;s just pure madness. That&#39;s why when we saw many companies rushing to build an App Center replacement, which is the easiest thing to do when you are a business and want to get customers, we didn&#39;t bother. It&#39;s not the right solution to the needs developers have.</p>
<p>
Developers need a quick way to build and run apps to previsualize changes. You can build your own solution, use <a href="https://shopify.engineering/shopify-tophat-mobile-developer-testing">Shopify&#39;s tophat</a>, or <a href="https://docs.tuist.dev/en/guides/features/previews">use Tuist Previews</a>, but once you have something like this and educate not just developers but everyone, you&#39;ll make everyone part of the development process, not just developers, and this is a unique strength that you can have as an organization to build better products.</p>
<p>
If web has got this, we can have it in app development too.</p>
<p>
Imagine being on a PR and commenting, &quot;Can you build a preview for me?&quot; Or even better, chatting with your LLM of choice and saying, &quot;Can I try the latest changes from main?&quot; and getting an email with a preview link. We&#39;ll get there, and <a href="/blog/2025/02/12/vm">commoditization of virtualization</a> is a key piece in enabling this.</p>
<h2 id="4.-complexities" tabindex="-1" class="marketing__blog_post__body__content__heading">
4. Complexities<a href="#4.-complexities" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 4. Complexities"></a></h2>
<p>
In large modular Xcode projects, complexity gets in the way. Complex errors like &quot;framework not found&quot; that people can&#39;t debug lead to cleaning derived data. Teams wanting to introduce new dependencies in the graph and not understanding the consequences of their actions can lead to unexpected behavior and bugs in the app.</p>
<p>
Some complexity is accidental, other is inherent. Regardless of the type of complexity, if you <a href="https://www.youtube.com/watch?v=zKyv-IGvgGE&t=1037s">don&#39;t compress it</a>, you&#39;ll have a team of frustrated developers who waste their creative energy figuring out their tools and processes as opposed to building better apps.</p>
<p>
We are big fans of the Ruby and Ruby on Rails mantra of optimizing for developer happiness. Usually, complexities, while an exciting challenge to understand for engineers, diminish any happiness in the process. Therefore, we find it quite useful to identify where complexity lies to ask oneself, &quot;Is this fun?&quot;</p>
<p>
This question drives many of the product decisions that we make at Tuist and helps us determine which complexities we need to compress:</p>
<ul>
  <li>
Managing and evolving Xcode projects is not fun: We conceptually compress it with a DSL.  </li>
  <li>
Waiting for half an hour to get feedback in a PR is not fun: We conceptually compress the complexities to optimize the processes (it&#39;s just one command, <code class="inline">tuist cache</code>).  </li>
  <li>
Signing successfully is not fun: We&#39;ll conceptually compress the intricacies of managing certificates and profiles and signing for teams.  </li>
</ul>
<p>
Eliminating complexities to make development fun should be an <a href="https://en.wikipedia.org/wiki/The_Infinite_Game">infinite game for teams</a>. It&#39;s ours, so if you prefer to delegate that to us, we&#39;d be glad to help.</p>
<h2 id="5.-flaky-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
5. Flaky tests<a href="#5.-flaky-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 5. Flaky tests"></a></h2>
<p>
Flaky tests are non-deterministic tests—tests that sometimes pass and other times fail. Flaky tests are damn annoying. You open a PR, wait for a potentially slow CI to complete, just to see that a test unrelated to your changes failed. Then you retry because you are too busy and too far from that test to fix it, and move on. But someone else runs into the same issue, and another person too, and your team is wasting their time throughout the day. But it&#39;s all fine because your &quot;test coverage&quot; is high, and that&#39;s all that matters at the end of the day, right? I dare to say little to no flakiness is even better than high test coverage, which at the end of the day is not really an indicator of the quality of your tests or your business logic. This sounds too controversial, but I had to say it.</p>
<p>
Flakiness is a momentum disruptor. A huge one. One that goes unnoticed and only becomes apparent when it&#39;s too serious.</p>
<p>
And with Swift Testing encouraging parallelization, if you have flakiness in your codebase, it might become more apparent. Swift is not a functional programming language where state navigates deterministically in one direction. Global state will appear somewhere, making your tests and logic prone to race conditions, and voila—flakiness is there. If you think flakiness won&#39;t happen to you, think again.</p>
<p>
Sadly, the tooling to address this is very scarce. Most of the tooling in the ecosystem consists of native apps, which don&#39;t have a shared globally accessible database where one can track how a test yields different results over time. Some CI platforms like <a href="https://buildkite.com/resources/blog/fixing-flaky-tests/">Buildkite</a> provide a solution for it, but since they don&#39;t have an understanding of the graph, they approximate a fingerprint to determine if a test has changed or not, disregarding the dependencies of the test. Tuist is graph-aware, so we can precisely calculate that at the module level and provide teams with a <a href="https://docs.tuist.dev/en/guides/develop/selective-testing">selective testing</a> solution that&#39;s very accurate. And we just recently added support for Xcode projects, so you can use it in your projects already.</p>
<h2 id="closing-thoughts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing thoughts<a href="#closing-thoughts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing thoughts"></a></h2>
<p>
Your team is a valuable source of creative energy. Don&#39;t waste it. Really. Spend some time understanding what hampers their momentum, and invest in mitigating those factors. And if you need a hand with it, we&#39;ll be more than happy to help.</p>
<p>
We are obsessed with making developers happy building apps, and we&#39;ve made this our full-time job. Through our solutions, we&#39;ve proved that abstracting the platform with something like React Native or replacing the build system with all the complexity of a build system like Bazel is not necessary. It&#39;s possible with your existing toolchain, believe us.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Generated Projects: why generate Xcode projects in 2025 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn why Tuist Generated Projects (Xcode project generation) are still relevant for scaling Xcode projects in 2025. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/25/project-generation"/>
      <id>https://tuist.dev/blog/2025/02/25/project-generation</id>
      <updated>Tue, 25 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
With Apple unifying and open-sourcing the <a href="https://www.swift.org/blog/the-next-chapter-in-swift-build-technologies/">build system</a> across SwiftPM and Xcode, and <a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes">Xcode 16</a> addressing the frequent Git conflicts, you might wonder about the continued relevance of Tuist Generated Projects and Xcode project generation. In this guide, we&#39;ll explore the current landscape and share our optimistic vision for the future of the ecosystem.</p>
<h2 id="the-challenges-of-modular-xcode-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
The challenges of modular Xcode projects<a href="#the-challenges-of-modular-xcode-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The challenges of modular Xcode projects"></a></h2>
<p>
Managing a modular Xcode project in 2025 still presents unique challenges. At scale, configuring the right build settings and phases to link frameworks, libraries, and copy dynamic modules becomes increasingly complex. When your project contains dozens or even hundreds of modules, visualizing the dependency graph to make informed changes becomes difficult.</p>
<p>
We&#39;ve observed that your projects might occasionally compile successfully due to the build system sharing derived data across build steps. However, this can lead to unexpected issues with debugging tools or SwiftUI previews.</p>
<p>
As applications expand to offer more products and support multiple platforms, <strong>modularization becomes not just beneficial but necessary.</strong> It&#39;s a sound architectural practice that enables you to use Swift access levels to define clear boundaries, making your applications more maintainable and allowing the compiler to optimize code effectively.</p>
<h2 id="the-industry's-response" tabindex="-1" class="marketing__blog_post__body__content__heading">
The industry&#39;s response<a href="#the-industry's-response" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The industry's response"></a></h2>
<p>
The ecosystem is actively addressing these challenges. The growing adoption of SwiftPM as a project manager demonstrates developers&#39; desire for simpler solutions to complex modular projects. While SwiftPM brings clarity by avoiding the complexities of &quot;build phases&quot; or &quot;build settings&quot; terminology, it represents an evolving approach that continues to mature.</p>
<p>
Companies like <a href="https://medium.com/bumble-tech/scaling-ios-at-bumble-239e0fa009f2">Bumble</a> have contributed valuable insights by openly sharing benchmarks about developer experience challenges with large modular codebases using SwiftPM. These conversations are crucial for driving improvements in the ecosystem.</p>
<h2 id="project-generation:-enhancing-accessibility-and-performance" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project generation: Enhancing accessibility and performance<a href="#project-generation:-enhancing-accessibility-and-performance" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project generation: Enhancing accessibility and performance"></a></h2>
<p>
Since 2017, we&#39;ve been working to address these challenges, first by creating <a href="https://github.com/tuist/XcodeProj">XcodeProj</a> for working with <code class="inline">.pbxproj</code> files, then developing Tuist as a project generator. Other tools like <a href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a> emerged with different approaches, giving developers options based on their specific needs.</p>
<p>
In 2025, project generation continues to play a vital role by:</p>
<ul>
  <li>
Making modular codebase management at scale accessible to all developers  </li>
  <li>
Optimizing build times through features like <a href="https://docs.tuist.dev/en/guides/develop/cache">cache</a> without requiring the complexity of systems like Bazel  </li>
</ul>
<p>
For teams dealing with extended CI turnaround times—sometimes exceeding an hour—these optimizations transform the development workflow and dramatically improve productivity.</p>
<h2 id="an-optimistic-future" tabindex="-1" class="marketing__blog_post__body__content__heading">
An optimistic future<a href="#an-optimistic-future" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to An optimistic future"></a></h2>
<p>
The future looks promising for iOS development tooling. The new <a href="https://www.swift.org/blog/the-next-chapter-in-swift-build-technologies/">swift-build</a> system, with the <a href="https://github.com/swiftlang/swift-driver">swift-driver</a>&#39;s content-addressable store (CAS), suggests that Apple is actively working on addressing core optimization challenges.</p>
<p>
While we can&#39;t predict exactly how SwiftPM will evolve, Apple has both the expertise and resources to revolutionize their development foundations by incorporating lessons from ecosystems like <a href="https://gradle.org">Gradle</a> and <a href="https://bazel.build">Bazel</a>. The emergence of AI, LLMs, and innovative editors is creating exciting opportunities for Xcode to expand its capabilities and experiences.</p>
<p>
At Tuist, we&#39;re committed to building a complementary productivity platform that extends these native foundations. We&#39;re continually expanding our feature set for standard Xcode projects, as demonstrated by our recent <a href="/blog/2025/02/18/selective-testing-for-xcode-projects">selective testing for Xcode projects</a> feature.</p>
<p>
The iOS development landscape is evolving rapidly, with multiple solutions working in tandem to create the best possible experience. As tools mature and new approaches emerge, developers will benefit from increased flexibility, improved performance, and smoother workflows.</p>
<p>
If you&#39;re a developer, lead, or head of a mobile organization interested in designing a thriving development environment, <a href="https://cal.tuist.dev/team/tuist/tuist">let&#39;s chat</a>. We&#39;re always eager to learn from and support organizations in making app development the most enjoyable experience possible.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Selective Testing for all Xcode projects ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Run only the tests affected by your changes with Tuist Selective Testing for Xcode projects. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/18/selective-testing-for-xcode-projects"/>
      <id>https://tuist.dev/blog/2025/02/18/selective-testing-for-xcode-projects</id>
      <updated>Tue, 18 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Re-running all tests on the CI or locally is a waste of time, resources, and money, especially as your codebase grows and your test suite suddenly has thousands of tests. Tuist Selective Testing lets you run tests selectively and skip those that were not impacted by your changes.</p>
<p>
While Tuist has had support for selective testing for a while now, it has been available only to those organizations that used Tuist to generate their Xcode projects and used the <code class="inline">tuist test</code> command to run their tests. </p>
<p>
We&#39;re excited to announce that we&#39;re now making selective testing available to <em>all</em> Xcode projects, regardless of your setup, by extending the <code class="inline">xcodebuild</code> CLI:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist xcodebuild test -scheme App -destination &quot;name=iPhone 16&quot;    </shiki-highlight>
  </div>
</div>
<p>
That&#39;s really almost all you need to do to dramatically speed up running your tests on the CI or locally. And yes, this feature also works if you modularized your app with local packages 📦</p>
<h2 id="get-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Get started<a href="#get-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Get started"></a></h2>
<p>
If you want to see selective testing of Xcode projects in action, check out the video below:</p>
<iframe title="Selective testing" width="560" height="315" src="https://videos.tuist.dev/videos/embed/9ac56b06-130f-4b76-af75-3b55545c4851" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<p>
To get started with selective testing, you need to first <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist">install Tuist</a>. Once installed, you can run your tests almost as if you were using the <code class="inline">xcodebuild</code> CLI. The only difference being that you need to prefix the <code class="inline">xcodebuild</code> command with <code class="inline">tuist</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist xcodebuild test -scheme App -destination &quot;name=iPhone 16&quot;    </shiki-highlight>
  </div>
</div>
<p>
Once your tests have run, Tuist will store your selective test results. Let&#39;s try to run the tests again:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist xcodebuild test -scheme App -destination &quot;name=iPhone 16&quot;
# There are no tests to run, exiting early...    </shiki-highlight>
  </div>
</div>
<p>
...and that&#39;s it! You have now successfully used selective testing to skip running tests that have not been impacted by your changes.</p>
<p>
If you want to test out this feature in a demo project, you can clone this <a href="https://github.com/tuist/xcode_project_with_tests">repository</a> and run the commands from above.</p>
<h2 id="how-it-works" tabindex="-1" class="marketing__blog_post__body__content__heading">
How it works<a href="#how-it-works" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How it works"></a></h2>
<p>
When you run <code class="inline">tuist xcodebuild test</code>, Tuist does a couple of things:</p>
<ul>
  <li>
Computes hashes for all your modules in your project  </li>
  <li>
Adds <code class="inline">-skip-testing</code> flags to the <code class="inline">xcodebuild</code> command with the modules that have not changed since the last successful run, based on their hash  </li>
  <li>
If the <code class="inline">test</code> command succeeds, Tuist stores selective testing results  </li>
</ul>
<p>
Let&#39;s go step by step using the <a href="https://github.com/tuist/xcode_project_with_tests">sample</a> posted in the previous section. We can use the <code class="inline">tuist graph</code> command to see the structure of our project (and yes, <code class="inline">tuist graph</code> now also works for any Xcode project):</p>
<p>
  <img src="/marketing/images/blog/2025/02/18/selective-testing-for-xcode-projects/graph.png" alt="Graph of an Xcode project with tests">
</p>
<p>
The important dependency relations are:</p>
<ul>
  <li>
<code class="inline">AppFrameworkTests</code> depends on <code class="inline">AppFramework</code>  </li>
  <li>
<code class="inline">AppTests</code> depends on <code class="inline">App</code> and transitively on <code class="inline">AppFramework</code>  </li>
</ul>
<p>
When we run the tests for the first time, Tuist first converts your Xcode project to an internal representation called <code class="inline">XcodeGraph</code> (for more details, see our previous <a href="https://tuist.dev/blog/2025/02/11/mapping-xcodeproj-to-xcodegraph">blog post</a> on this topic). Then Tuist computes the hashes using the same mechanism as we do for <a href="https://docs.tuist.dev/en/guides/develop/cache#cache">binary cache</a>, which has been battle-tested by now.</p>
<p>
On the first successful run, we store the hashes we just computed – locally and remotely (if you have a <a href="https://docs.tuist.dev/en/server/introduction/accounts-and-projects#projects">Tuist project</a> set up). On a subsequent run, Tuist can skip all tests if nothing changes. But what if something <em>did</em> change?</p>
<p>
Let&#39;s say we change something in the <code class="inline">App</code> module. When we run the tests again, Tuist will recompute the hashes and compare them with the stored ones. Since the <code class="inline">App</code> module has changed and <code class="inline">AppTests</code> depends on this module, Tuist will run the tests for <code class="inline">AppTests</code> – but <em>not</em> for <code class="inline">AppFrameworkTests</code> as the hash for that module has not been impacted by our changes! </p>
<p>
However, if we do update the <code class="inline">AppFramework</code> module, then Tuist will run the tests both for <code class="inline">AppFrameworkTests</code> <em>and</em> <code class="inline">AppTests</code> as <code class="inline">AppTests</code> transitively depends on <code class="inline">AppFramework</code> through <code class="inline">App</code>. </p>
<p>
How much can Tuist skip in your project very much depends on how it&#39;s structured. The selective testing will be more effective if your project is modular and your modules are well-separated into separate layers, reducing interdependencies between them. For example, it&#39;s a good idea to have a &quot;feature&quot; layer where no feature can depend on another feature, only on the &quot;core&quot; layer.</p>
<h2 id="extending-xcodebuild" tabindex="-1" class="marketing__blog_post__body__content__heading">
Extending xcodebuild<a href="#extending-xcodebuild" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Extending xcodebuild"></a></h2>
<p>
Extending <code class="inline">xcodebuild</code> with selective testing is yet another step in meeting developers where they are by extending tools most of the community already uses, rather than building completely new abstractions. The main benefit of using <code class="inline">tuist xcodebuild</code> as of now is to get access to selective testing. However, we recommend opting in to using <code class="inline">tuist xcodebuild</code> now, so you continuously benefit from new improvements as we ship them, such as detailed analytics and insights of your tests and builds.</p>
<p>
Optimizing projects and their interactions is key to making the most of one of the most valuable resources—engineering time. To achieve this, you need actionable insights that inform your decisions. That&#39;s why we&#39;re committed to providing you with valuable data to help you answer critical questions and create the most efficient development environment:</p>
<ul>
  <li>
Which test is the most flaky and disrupting workflow?  </li>
  <li>
What targets are becoming compilation bottlenecks, limiting parallelization?  </li>
  <li>
Which modules would benefit from additional testing?  </li>
</ul>
<p>
You can expect these kinds of insights to be soon available in our Tuist dashboard, which is also getting a facelift. Here&#39;s a sneak peak, coming later this year:</p>
<p>
  <img src="/marketing/images/blog/2025/02/18/selective-testing-for-xcode-projects/dashboard-sneak-peek.png" alt="Dashboard sneak peek">
</p>
<h2 id="wrapping-up" tabindex="-1" class="marketing__blog_post__body__content__heading">
Wrapping up<a href="#wrapping-up" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Wrapping up"></a></h2>
<p>
Selective testing is a powerful feature that can save you a lot of time and resources. It&#39;s available for all Xcode projects, regardless of your setup, and can be used both locally and on the CI. To learn more about how to use it, check out our <a href="https://docs.tuist.dev/en/guides/develop/selective-testing">documentation</a>.</p>
<p>
We&#39;re also always keen to hear your feedback – if you take selective testing for a spin, let us know how it goes at:</p>
<ul>
  <li>
<a href="https://community.tuist.dev/">Our community forum</a>  </li>
  <li>
<a href="https://slack.tuist.io/">Slack</a>  </li>
  <li>
<a href="https://fosstodon.org/@tuist">Mastodon</a>  </li>
  <li>
<a href="https://bsky.app/profile/tuist.dev">Bluesky</a>  </li>
</ul>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Announcing our first Tuist ambassadors ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We are excited to introduce our first Tuist ambassadors. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/18/ambassadors"/>
      <id>https://tuist.dev/blog/2025/02/18/ambassadors</id>
      <updated>Tue, 18 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist&#39;s approach to building technology has always been driven by being community-first. Tuist is what it is today thanks to our wonderful and talented community—people who show up and contribute, whether through issues, pull requests, or conference talks.</p>
<p>
Among these contributors, some individuals have gone above and beyond. For a long time, we&#39;ve felt a deep sense of gratitude toward them. Inspired by other community-driven projects like Dagger, we <a href="https://community.tuist.dev/t/announcing-the-tuist-ambassadors-program/157">announced</a> the Tuist Ambassadors Program in October 2024.</p>
<p>
Today, I am honored to introduce you to our first Tuist ambassadors. But before we highlight them, let me share more details about the program.</p>
<h2 id="the-program" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Program<a href="#the-program" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Program"></a></h2>
<p>
Ambassadors are individuals passionate about Tuist and its mission. They are selected based on their contributions to the project and their ability to represent Tuist within the community. In recognition of their efforts, Tuist will publicly acknowledge their contributions and support their professional growth. Additionally, ambassadors will receive exclusive swag and assistance when attending events.</p>
<p>
As we shape the direction of the project, we will collaborate closely with ambassadors to ensure alignment with our vision and goals. The role lasts for one year to allow for rotation, and we continuously welcome new ambassadors when we recognize outstanding contributions.</p>
<h2 id="meet-the-ambassadors" tabindex="-1" class="marketing__blog_post__body__content__heading">
Meet the Ambassadors<a href="#meet-the-ambassadors" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Meet the Ambassadors"></a></h2>
<h3 id="andy-kolean" tabindex="-1" class="marketing__blog_post__body__content__heading">
Andy Kolean<a href="#andy-kolean" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Andy Kolean"></a></h3>
<p>
<a href="https://github.com/ajkolean">Andy</a> first engaged with Tuist by suggesting an enhancement to our graph command in <a href="https://community.tuist.dev/t/enhancing-tuists-graph-command-with-interactive-graph/225">this topic</a>. He then followed up with an <a href="https://github.com/tuist/XcodeGraph/pull/87">amazing contribution</a> that introduced a solution to map Xcode projects and workspaces to Tuist’s internal models, specifically through <a href="https://github.com/tuist/xcodegraph">XcodeGraph</a>.</p>
<p>
By bridging these domains, Andy’s work not only advances our mission to meet developers where they are but also enables a more high-level interaction with Xcode projects and workspaces. His contributions have had a profound impact on Tuist’s evolution.</p>
<h3 id="łukasz-lech" tabindex="-1" class="marketing__blog_post__body__content__heading">
Łukasz Lech<a href="#łukasz-lech" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Łukasz Lech"></a></h3>
<p>
<a href="https://github.com/leszko11">Łukasz</a> has been making top-notch contributions to Tuist since 2020, from his home in the beautiful city of Wrocław, Poland. A strong advocate for Tuist, he has consistently highlighted its value in making Xcode projects and workspaces more manageable. He actively promotes Tuist at every opportunity, including at the <a href="https://swiftheroes.com/swiftheroes-2024/speaker/AK9KM9/">Swift Heroes</a> conference in 2024.</p>
<h3 id="loyle-(sang-hyeok-kim)" tabindex="-1" class="marketing__blog_post__body__content__heading">
Loyle (Sang Hyeok Kim)<a href="#loyle-(sang-hyeok-kim)" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Loyle (Sang Hyeok Kim)"></a></h3>
<p>
Tuist has gained significant popularity in South Korea, in large part thanks to dedicated contributors like <a href="https://github.com/sanghyeok-kim">Loyle</a>. He not only delivers exceptional contributions but also plays a crucial advocacy role, spreading the word about Tuist within the Korean developer community.</p>
<h3 id="anıl-taşkıran" tabindex="-1" class="marketing__blog_post__body__content__heading">
Anıl Taşkıran<a href="#anıl-taşkıran" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Anıl Taşkıran"></a></h3>
<p>
<a href="https://www.linkedin.com/in/aniltaskiran/">Anıl</a> has been a long-time supporter of Tuist, especially in the Turkish community. He works at Trendyol, one of the largest e-commerce companies in Turkey, where he has been instrumental in introducing Tuist to his colleagues. Trendyol has been using Tuist for multiple years now and has been <a href="https://tuist.dev/blog/2024/12/16/trendyol">vocal about its benefits</a>.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing Words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing Words"></a></h2>
<p>
I couldn&#39;t be more proud of our ambassadors and the impact they have on the Tuist community. Over the coming months, we will continue working on new community initiatives to foster collaboration and innovation—key elements in building the most useful productivity tool for app developers.</p>
<p>
Thank you to all our contributors, and a special congratulations to our first Tuist ambassadors!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Catching up with modern developer experiences through macOS virtualization ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We discuss the cost of running macOS-dependent workflows remotely and how we can catch up with modern developer experiences through macOS virtualization. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/12/vm"/>
      <id>https://tuist.dev/blog/2025/02/12/vm</id>
      <updated>Wed, 12 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When we discuss the developer experiences we&#39;d like to provide at Tuist and what we need to enable them, we often find ourselves discussing the cost of running macOS-dependent workflows remotely.</p>
<p>
In other ecosystems, like the web, workflows can run in Linux environments that can be easily virtualized with technologies like <a href="https://www.docker.com">Docker</a> or <a href="https://podman.io">Podman</a>. Even browsers can become containers with projects like <a href="https://webcontainers.io">WebContainers</a>, in which you can run a <a href="https://nodejs.org/en">NodeJS</a> instance. <a href="https://stackblitz.com">StackBlitz</a> leverages this technology to include interactive code examples in websites. Other projects like <a href="https://replit.com">Replit</a> or <a href="https://bolt.new">Bolt</a> provide full-fledged AI experiences for creating and running code. As a project that likes to innovate in the developer experience space, we can&#39;t help but feel that we are lagging behind. But what would it take to catch up?</p>
<h2 id="a-macos-dependent-world" tabindex="-1" class="marketing__blog_post__body__content__heading">
A macOS-dependent world<a href="#a-macos-dependent-world" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A macOS-dependent world"></a></h2>
<p>
It&#39;s well known that developing apps for the Apple environment is tightly coupled with macOS as a host. Although Swift and its toolchain are taking a different direction to expand into new environments, Apple development remains heavily dependent on proprietary macOS tools and frameworks. Even UI technologies like <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a> remain in Apple&#39;s proprietary domain, making it difficult to port to other platforms or leverage it to create new AI-based coding experiences that build on SwiftUI internals.</p>
<p>
Ideally, this wouldn&#39;t be the case, but with Apple being a hardware and service company, the likelihood of the toolchain breaking its dependency on macOS is very low. From a business perspective, such an investment makes little sense. However, who knows what the future holds? They might surprise us.</p>
<p>
If breaking the dependency with macOS isn&#39;t an option, what&#39;s the alternative? Let&#39;s talk about virtualization.</p>
<h2 id="virtualization-of-macos-environments" tabindex="-1" class="marketing__blog_post__body__content__heading">
Virtualization of macOS environments<a href="#virtualization-of-macos-environments" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Virtualization of macOS environments"></a></h2>
<p>
Virtualization allows you to create isolated macOS environments on your machine. Apple released a framework called <a href="https://developer.apple.com/documentation/virtualization">Virtualization</a> to facilitate this. Docker and Podman are similar technologies for Linux environments. Docker revolutionized the way we build and run applications. Suddenly, your cloud provider didn&#39;t have to provide you with the exact environment you needed—you simply gave them your <a href="https://github.com/opencontainers/image-spec">OCI image</a>, and they ran it.</p>
<p>
Most CI providers use virtualization to prevent polluting a host&#39;s environment. They create ephemeral environments for each build. The options to virtualize were quite limited and proprietary, with <a href="https://veertu.com/anka-build/">Anka</a> being one example. These CI providers not only had to solve the problem of virtualization (which was delegated to third-party companies offering proprietary technology) but also had to develop the technology to orchestrate host environments and distribute workloads within them.</p>
<p>
Unlike Docker environments, which cloud providers can provision in seconds via API, achieving the same thing in macOS is more costly. Images are not as lightweight as Docker images, so you can&#39;t pull them lazily since they can take minutes to download. Additionally, until recently, accessing Apple hardware was a manual process with data centers. AWS <a href="https://aws.amazon.com/ec2/instance-types/mac/">changed the game</a> by providing APIs to spin up new machines. The complexity lay in maintaining a pool of Apple hardware, warmed with images and ready to run workloads.</p>
<p>
As mentioned earlier, innovation in this space happened behind closed doors and was oriented toward building continuous integration. But thanks to the beauty of software, things are getting commoditized, which opens a world of opportunities.</p>
<h2 id="commoditization-of-virtualization" tabindex="-1" class="marketing__blog_post__body__content__heading">
Commoditization of virtualization<a href="#commoditization-of-virtualization" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Commoditization of virtualization"></a></h2>
<p>
It&#39;s inevitable that software becomes commoditized through open source. Commoditization is the process of making goods or services more accessible and affordable to more people. Consider the process of building a web app today: you build it using an open-source framework and technologies, with an open-source programming language, that runs in open-source virtualization technology, on an open-source operating system, that most likely runs on proprietary hardware. macOS virtualization has been slow to commoditize, but that&#39;s changing.</p>
<p>
Recently, we came across two efforts: <a href="https://github.com/trycua/lume">Lume</a> and <a href="https://github.com/macvmio">macvm</a>. Both are building technologies to commoditize macOS virtualization. macvm is also developing <a href="https://github.com/macvmio/fugaci">fugaci</a>, a technology to orchestrate workload distribution using Kubernetes. We&#39;re getting closer to a point where an AWS key might be the only thing needed to bring CI to your organization, with solutions like GitHub Actions or <a href="https://buildkite.com">Buildkite</a> serving as frontends to runners. We&#39;re not far from that world.</p>
<p>
This might not be great news for CI companies that have built their businesses around proprietary technologies. But for a small team of 4 people like us, who can&#39;t afford the cost of developing and maintaining such commodities, it&#39;s a game-changer. We can focus on innovating in the developer experience space rather than building yet another version of technology that others have built before.</p>
<h2 id="blurring-local-and-remote-environments" tabindex="-1" class="marketing__blog_post__body__content__heading">
Blurring local and remote environments<a href="#blurring-local-and-remote-environments" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Blurring local and remote environments"></a></h2>
<p>
For many years, virtualization served CI businesses. CI is an easy way sell to investors and customers—you don&#39;t need to convince developers and organizations about its necessity. But what else could we do with virtualization? What can we learn from the web and other uses of Linux-based virtualization technologies? These are the questions we&#39;re interested in exploring and solving at Tuist.</p>
<p>
Proprietary virtualization technologies and YAML naturally lead to automation that can&#39;t be debugged easily. Having to push code to see if a pipeline does what it&#39;s supposed to do is the result of investing in closed solutions. Now imagine this: you can have the same virtualization technology that you use in CI on your local machine. Suddenly, the same workflow that will run in CI is runnable locally, whether it&#39;s an <code class="inline">xcodebuild</code> command or your own workflow:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist xcodebuild -project MyApp -scheme MyApp -vm local:macos-sequoia-xcode:latest    </shiki-highlight>
  </div>
</div>
<p>
Let that sink in. Automation becomes easier to debug. What if you could then run the same workflow remotely with a version of Xcode of your choice?</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist xcodebuild -project MyApp -scheme MyApp -vm remote:macos-sequoia-xcode-15:latest    </shiki-highlight>
  </div>
</div>
<p>
The logs would be forwarded to your local machine, making it feel as if things were running locally. This is similar to the <code class="inline">fly deploy</code> command for deploying apps to <a href="https://fly.io">Fly</a>, where the image can be built remotely, but everything feels local. Isn&#39;t that amazing?</p>
<p>
Why hasn&#39;t this happened before? We wonder the same... Virtualization is costly, so only companies with substantial resources could afford to innovate. Additionally, companies with resources often find it less risky to mimic other models and compete on the value-cost tradeoff than to innovate. Here comes Tuist: poor but sexy. We can innovate because we&#39;re not afraid to explore new domains, and the cost is decreasing.</p>
<p>
If you thought that was enough, you&#39;re wrong. Have you noticed that most solutions in the space require you to trigger workflows either from a local environment or a CI environment? This is because they don&#39;t want to solve virtualization. But imagine if it were possible. You could enable workflows triggered from the web, just like triggering a GitHub Action workflow.</p>
<p>
Let&#39;s say you&#39;re reviewing a PR and want to get a preview build. You could click a button, and a preview build would be triggered in a macOS environment, with the preview shared with you. Forget about those nightly builds or <a href="https://appcenter.ms">App Center</a> replacements. Those models are fundamentally broken, yet we keep mimicking them and racing to create alternatives. This opens a world of possibilities—it could be a preview, a release, or even on-the-fly signing to allow someone to install a release on their device.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing Words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing Words"></a></h2>
<p>
Apple decoupling app development from macOS is a dream that might never come true. However, the commoditization of virtualization technologies is a reality, and Tuist is going to leverage it to provide a better developer experience. Transitioning from being a purely client-side technology through our CLI to a web-based platform where the CLI is an interface to the platform positions us well to blur web and client boundaries in ways that ecosystems like the web have been doing for years.</p>
<p>
While we don&#39;t have experience in building infrastructure, we have a strong appetite for learning about it and solving its challenges—not only to build better experiences ourselves but also to invite other companies and developers to innovate in the space, as we did with other commodities we&#39;ve released in the past, like project generation and the <a href="https://github.com/tuist/xcodeproj">XcodeProj</a> parser.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Mapping XcodeProj to XcodeGraph ]]></title>
      
      
      <author>
        <name><![CDATA[ Andrew Kolean ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Taking the scenic route through the XcodeGraphMapper. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/11/mapping-xcodeproj-to-xcodegraph"/>
      <id>https://tuist.dev/blog/2025/02/11/mapping-xcodeproj-to-xcodegraph</id>
      <updated>Tue, 11 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hey everyone, Andy here! </p>
<p>
I&#39;ve been deep in the weeds connecting <a href="https://github.com/tuist/xcodeproj"><strong>XcodeProj</strong></a> to <a href="https://github.com/tuist/XcodeGraph"><strong>XcodeGraph</strong></a>, turning raw .xcworkspace or .xcodeproj data into a delightful graph structure.</p>
<p>
You might be wondering, &quot;Why do we need a graph for something as &#39;simple&#39; as an Xcode project?&quot; Let&#39;s just say that once you start exploring advanced analysis, partial builds, or illusions hidden in tangly references, you&#39;ll be glad everything ends up in a single, coherent &quot;map&quot;.</p>
<p>
In this post, I&#39;ll walk through <em>how</em> the mapping process works, <em>which pitfalls</em> we cover, and <em>why</em> you might want to harness it for your own projects.</p>
<h2 id="why-bother?-the-overgrown-secret-garden" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why bother? The overgrown secret garden<a href="#why-bother?-the-overgrown-secret-garden" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why bother? The overgrown secret garden"></a></h2>
<p>
Sometimes, your codebase feels like an overgrown secret garden: you open Xcode, spot multiple targets referencing frameworks, Swift packages, or script phases, but the big picture is elusive. XcodeGraph helps transform that hidden mess into a directed acyclic graph (DAG)—in simpler terms, a neat diagram of who depends on what. But it’s more than just a DAG: XcodeGraph provides higher-level models and user-friendly properties that abstract away the complexity, making the project structure easier to understand and interact with.</p>
<p>
In contrast, XcodeProj offers a near 1:1 mapping of the .pbxproj format to Swift. It’s precise but low-level, exposing the raw details without much abstraction. That’s where XcodeGraphMapper comes in: it’s the pipeline that unifies this raw data into the more accessible structure that XcodeGraph provides.</p>
<p>
The benefits are huge. Imagine wanting to only test modules that changed or to inspect a suspicious missing framework from a test target. Once your project is represented as a DAG with rich, user-friendly models, you can see those connections in a single pass. No more rummaging through thousands of lines in .pbxproj, just a straightforward structure to query or visualize.</p>
<h2 id="why-tuist-&-you-should-care" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why Tuist &amp; you should care<a href="#why-tuist-&-you-should-care" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why Tuist & you should care"></a></h2>
<p>
The XcodeGraphMapper will unlock many features that would have previously been reserved only to projects generated with Tuist to any Xcode projects – generated or not. Here are some examples of what XcodeGraphMapper makes possible:</p>
<h3 id="tuist-graph-for-everyone" tabindex="-1" class="marketing__blog_post__body__content__heading">
tuist graph for everyone<a href="#tuist-graph-for-everyone" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to tuist graph for everyone"></a></h3>
<p>
We&#39;re enabling <code class="inline">tuist graph</code> for Tuist projects not generated with Tuist. Just run it and see your project&#39;s nodes and edges, maybe unearthing hidden complexities you never noticed.</p>
<h3 id="interactive-graph-&-tools" tabindex="-1" class="marketing__blog_post__body__content__heading">
Interactive graph &amp; tools<a href="#interactive-graph-&-tools" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Interactive graph & tools"></a></h3>
<p>
Because it&#39;s a typed DAG, building a UI to click around each target, framework, or package is straightforward. Debugging cyclical references becomes a matter of visual search, not illusions.</p>
<h3 id="selective-testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Selective testing<a href="#selective-testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Selective testing"></a></h3>
<p>
Need to test only the modules that changed? Tuist uses the constructed DAG to detect which sub-trees your commit touches, so you can skip retesting the entire orchard.</p>
<h3 id="easier-extensibility" tabindex="-1" class="marketing__blog_post__body__content__heading">
Easier extensibility<a href="#easier-extensibility" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Easier extensibility"></a></h3>
<p>
We no longer rely on arcane .pbxproj hacks. The DAG is stable, letting you do custom scripts or auto-gen docs with minimal friction.</p>
<p>
<em>(And if you&#39;re curious to see real</em> <strong>visual</strong> <em>graphs in action, I wrote a post in the community forum about the <a href="https://community.tuist.dev/t/xcodegraphgenerator-a-tool-to-visualize-tuist-xcode-project-dependencies/100">XcodeGraphGenerator</a>, plus a <a href="https://ajkolean.github.io/XcodeGraphGenerator/">live demo here</a> that shows what a friendly node-and-edge layout could look like. Check it out if you&#39;re a &quot;pics or it didn&#39;t happen&quot; type!)</em></p>
<h2 id="a-bird's-eye-tour:-step-by-step-through-xcodegraphmapper" tabindex="-1" class="marketing__blog_post__body__content__heading">
A bird&#39;s-eye tour: step by step through XcodeGraphMapper<a href="#a-bird's-eye-tour:-step-by-step-through-xcodegraphmapper" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A bird's-eye tour: step by step through XcodeGraphMapper"></a></h2>
<h3 id="step-1:-rummaging-for-.xcworkspace-or-.xcodeproj" tabindex="-1" class="marketing__blog_post__body__content__heading">
Step 1: Rummaging for .xcworkspace or .xcodeproj<a href="#step-1:-rummaging-for-.xcworkspace-or-.xcodeproj" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Step 1: Rummaging for .xcworkspace or .xcodeproj"></a></h3>
<p>
First, the mapper checks if you handed it a .xcworkspace, a single .xcodeproj, or a directory containing one or both. Think of it like rummaging around your desk drawers, <strong>XcodeGraphMapper</strong> systematically hunts for the star of the show (e.g., &quot;MyApp.xcodeproj&quot;) so it can read all your build settings and references.
If it&#39;s a workspace, we open it and see if it references multiple subprojects. If you gave us a direct .xcodeproj, we skip the rummaging and dive right in. And if you toss a random directory at us, we&#39;ll see if there&#39;s a .xcodeproj or .xcworkspace inside, so illusions about &quot;there&#39;s nothing here&quot; don&#39;t fool us.</p>
<h3 id="step-2:-chitchat-with-xcodeproj" tabindex="-1" class="marketing__blog_post__body__content__heading">
Step 2: Chitchat with XcodeProj<a href="#step-2:-chitchat-with-xcodeproj" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Step 2: Chitchat with XcodeProj"></a></h3>
<p>
Once we find the target file, we hand it to <strong>XcodeProj</strong>, our best friend for reading raw project data. It extracts everything from the main <code class="inline">PBXProject</code> to build phases, Swift packages, script references, like collecting puzzle pieces scattered everywhere.</p>
<h3 id="step-3:-marshaling-the-troops-(our-mappers)" tabindex="-1" class="marketing__blog_post__body__content__heading">
Step 3: Marshaling the troops (our mappers)<a href="#step-3:-marshaling-the-troops-(our-mappers)" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Step 3: Marshaling the troops (our mappers)"></a></h3>
<p>
Now come <strong>the mappers</strong>:</p>
<ul>
  <li>
<code class="inline">PBXProjectMapper</code> merges project-level data into a top-level &quot;Project&quot; object, calling sub-mappers for each target.  </li>
  <li>
<code class="inline">PBXTargetMapper</code> captures each target&#39;s product, frameworks, Swift packages, resources, scripts, you name it.  </li>
  <li>
<code class="inline">XCConfigurationMapper</code> unifies build configs and .xcconfig references into typed &quot;Settings.&quot;  </li>
  <li>
<code class="inline">XCSchemeMapper</code> scans .xcscheme for run/test actions, perfect for partial testing or environment variable analysis.  </li>
  <li>
<code class="inline">PathDependencyMapper</code> normalizes frameworks, .xcframeworks, or libraries into a domain &quot;dependency&quot; model so the graph sees them as a single node type.  </li>
</ul>
<p>
By the end, each target, resource, or scheme is turned into typed domain models, leaving no illusions behind.</p>
<h3 id="step-4:-one-graph-to-rule-them-all" tabindex="-1" class="marketing__blog_post__body__content__heading">
Step 4: One graph to rule them all<a href="#step-4:-one-graph-to-rule-them-all" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Step 4: One graph to rule them all"></a></h3>
<p>
Finally, we gather all domain objects into a single adjacency list, the <strong>Graph</strong>. Targets or packages become nodes, edges connect them. We store conditions like &quot;only watchOS&quot; or &quot;dynamic library&quot; so advanced features can filter or visualize them with ease. No illusions left behind, just a neat map to reference.</p>
<h2 id="concurrency:-just-enough-magic-to-not-block" tabindex="-1" class="marketing__blog_post__body__content__heading">
Concurrency: Just enough magic to not block<a href="#concurrency:-just-enough-magic-to-not-block" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Concurrency: Just enough magic to not block"></a></h2>
<p>
You&#39;ll see async/await calls in the code, but we haven&#39;t gone full parallel mania, trying to parallelize every little call. Instead, concurrency is primarily used to <strong>avoid blocking</strong> on certain system calls (like retrieving the developer directory via <code class="inline">xcode-select -p</code>) or scanning large directories. That means we can yield the thread while waiting, so you don&#39;t beachball if the OS is in a mood.</p>
<p>
We try to keep things straightforward: scanning, loading, and mapping in a single pipeline, step by step. It&#39;s simpler to maintain and still snappy enough for typical project sizes. Given our functional approach of mappers, we can easily parallelize more if needed – for now, parallelizing mapping of individual subprojects have been enough even for larger projects.</p>
<h2 id="edge-cases-&-subtle-quirks" tabindex="-1" class="marketing__blog_post__body__content__heading">
Edge cases &amp; subtle quirks<a href="#edge-cases-&-subtle-quirks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Edge cases & subtle quirks"></a></h2>
<h3 id="nested-subprojects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Nested subprojects<a href="#nested-subprojects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Nested subprojects"></a></h3>
<p>
Some folks place a .xcodeproj inside another .xcodeproj or do a container reference like &quot;container:../OtherProject.xcodeproj.&quot; Don&#39;t worry, XcodeGraphMapper systematically follows those references. It&#39;s basically unstoppable (unless you form a cycle of references, in which case we throw an error and raise an eyebrow).</p>
<h3 id="local-vs.-remote-swift-packages" tabindex="-1" class="marketing__blog_post__body__content__heading">
Local vs. remote Swift packages<a href="#local-vs.-remote-swift-packages" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Local vs. remote Swift packages"></a></h3>
<p>
Your package might be a local path or a remote Git URL pinned to a branch. Either way, we unify them under a single &quot;Package&quot; node in the final graph, so no confusion about which is which.</p>
<h3 id="schemes-&-scripts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Schemes &amp; scripts<a href="#schemes-&-scripts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Schemes & scripts"></a></h3>
<p>
Because we also read .xcscheme, we pick up test or run actions. That&#39;s how advanced commands figure out partial test runs or environment variables. We do the same for script phases, capturing them as typed &quot;TargetScript&quot; objects so you don&#39;t forget that magical &quot;Run Script&quot; step.</p>
<h3 id="odd-build-settings" tabindex="-1" class="marketing__blog_post__body__content__heading">
Odd build settings<a href="#odd-build-settings" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Odd build settings"></a></h3>
<p>
If your codebase is truly bizarre (custom resource bundling, anyone?), we either parse it with general logic or skip it if it&#39;s unrecognized. We also throw typed errors if something crucial is missing. That means we fail fast if you reference a non-existent file or we can&#39;t find the path to a subproject.</p>
<h2 id="a-small-example:-myapp-+-locallib-+-remotepackage" tabindex="-1" class="marketing__blog_post__body__content__heading">
A small example: MyApp + LocalLib + RemotePackage<a href="#a-small-example:-myapp-+-locallib-+-remotepackage" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A small example: MyApp + LocalLib + RemotePackage"></a></h2>
<p>
Let&#39;s say you have a .xcworkspace with a &quot;MyApp&quot; target that depends on:</p>
<ul>
  <li>
A local static library LocalLib.a  </li>
  <li>
A remote Swift package RemoteKit pinned to version 2.1  </li>
</ul>
<p>
<strong>XcodeGraphMapper</strong> sees your workspace, finds &quot;MyApp.xcodeproj,&quot; merges them with the PBXTargetMapper, notices &quot;MyApp&quot; depends on LocalLib.a and also calls XCPackageMapper for RemoteKit. Boom! That yields nodes in your final graph:</p>
<p>
<strong>MyApp → LocalLib.a → RemoteKit</strong></p>
<p>
If you run <code class="inline">tuist inspect implicit-dependencies</code>, you&#39;ll quickly see whether your tests also need &quot;RemoteKit,&quot; or if you forgot to link &quot;LocalLib.a&quot; for a certain config. Simple and clear.</p>
<h2 id="looking-to-the-horizon" tabindex="-1" class="marketing__blog_post__body__content__heading">
Looking to the horizon<a href="#looking-to-the-horizon" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Looking to the horizon"></a></h2>
<ul>
  <li>
<strong>Parallel Parsing</strong>: Right now, we parse subprojects in a single pass. If you have a monstrous codebase, we might expand concurrency so illusions fall away faster.  </li>
  <li>
<strong>Deeper Data</strong>: Apple might add new frameworks or build phases, no illusions stay hidden once we add them to the mappers.  </li>
  <li>
<strong>UI Tools</strong>: A typed DAG is perfect for BFS-based lint checks, doc generation, or a &quot;clickable&quot; interface to roam your codebase.  </li>
</ul>
<h2 id="wrapping-it-all-up" tabindex="-1" class="marketing__blog_post__body__content__heading">
Wrapping it all up<a href="#wrapping-it-all-up" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Wrapping it all up"></a></h2>
<p>
<strong>XcodeGraphMapper</strong> may sound niche, but it&#39;s the real hero bridging raw .xcworkspace or .xcodeproj references with the clarity of a graph-based approach. By the end of its pipeline, illusions vanish, references line up, and you&#39;re left with a single adjacency structure that&#39;s perfect for partial builds, advanced analysis, or simply not going bonkers rummaging through .pbxproj.
If you&#39;re as excited about illusions turning into clarity, definitely stay tuned. We&#39;re just scratching the surface of what a well-organized DAG can do.</p>
<p>
Thanks so much for reading, and huge thanks to Marek and the entire community for the encouragement and feedback. I can&#39;t wait to see how folks push these illusions aside in favor of a single, shining map.</p>
<p>
Happy Coding,</p>
<p>
Andy</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Deploy DocC documentation to Cloudflare Pages ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn how to deploy your DocC documentation to Cloudflare Pages. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/10/deploy-docc-cloudflare-pages"/>
      <id>https://tuist.dev/blog/2025/02/10/deploy-docc-cloudflare-pages</id>
      <updated>Mon, 10 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
If you need to deploy and host a <a href="https://www.swift.org/documentation/docc/">DocC documentation</a>, the go-to solution for documenting your Swift packages, on <a href="https://pages.cloudflare.com/">Cloudflare Pages</a>, this guide has you covered. Cloudflare Pages is a great alternative to GitHub Pages, especially if you want your documentation to live under a custom domain that you might already have on Cloudflare for that extra bit of polish ✨</p>
<p>
<strong>Note:</strong> We&#39;re assuming that you have a Cloudflare account set up. The examples will be using GitHub Actions, but you can adapt them to any CI/CD system you prefer.</p>
<h2 id="build-your-docc-documentation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build your DocC documentation<a href="#build-your-docc-documentation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build your DocC documentation"></a></h2>
<p>
We&#39;ll first need to build the DocC documentation. The easiest way is to add the <a href="https://github.com/swiftlang/swift-docc-plugin">DocC plugin</a> to your <code class="inline">Package.swift</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let package = Package(
    // name, platforms, products, etc.
    dependencies: [
        // other dependencies
        .package(url: &quot;https://github.com/swiftlang/swift-docc-plugin&quot;, from: &quot;1.1.0&quot;),
    ],
    targets: [
        // targets
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
You can check the documentation builds by running <code class="inline">swift package generate-documentation</code>. To make our lives easier on the CI, we&#39;ll generate the documentation into a specific directory and transform it for static hosting:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
swift package --allow-writing-to-directory .build/documentation generate-documentation --disable-indexing --output-path .build/documentation --transform-for-static-hosting --target YourProduct    </shiki-highlight>
  </div>
</div>
<p>
If you have multiple targets you want to generate the documentation for, we can leverage the new <a href="https://forums.swift.org/t/a-preview-of-doccs-support-for-combined-documentation/74373"><code class="inline">--enable-experimental-combined-documentation</code> flag</a> to generate a single documentation for all targets:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
swift package --allow-writing-to-directory .build/documentation generate-documentation --disable-indexing --output-path .build/documentation --transform-for-static-hosting --enable-experimental-combined-documentation --target YourProductA --target YourProductB    </shiki-highlight>
  </div>
</div>
<p>
With this new flag, each target will have its own section in the documentation. In Swift 6.1, this flag will even create an index page:</p>
<p>
  <img src="/marketing/images/blog/2025/02/10/deploy-docc-cloudflare-pages/combined-documentation.png" alt="Conmbined documentation">
</p>
<p>
We are very excited about this development as it will make it even easier to host documentation for packages with multiple products, which is quite common.</p>
<h2 id="set-up-cloudflare-pages" tabindex="-1" class="marketing__blog_post__body__content__heading">
Set up Cloudflare pages<a href="#set-up-cloudflare-pages" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Set up Cloudflare pages"></a></h2>
<p>
Let&#39;s first set up Cloudflare Pages by going to the <code class="inline">Workers &amp; Pages</code> page and creating a new project. Once you have connected your GitHub account, you can import a repository that contains your DocC documentation:</p>
<p>
  <img src="/marketing/images/blog/2025/02/10/deploy-docc-cloudflare-pages/workers-pages-create.png" alt="Create Workers &amp; Pages">
</p>
<p>
You can also follow the official <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-anything/">Cloudflare documentation</a>. Note that since we will be deploying the documentation from GitHub Actions, we&#39;ll want to disable automatic deployment in the settings of the Cloudflare Pages project.</p>
<h2 id="github-actions-pipeline" tabindex="-1" class="marketing__blog_post__body__content__heading">
GitHub Actions pipeline<a href="#github-actions-pipeline" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to GitHub Actions pipeline"></a></h2>
<p>
Now to the more interesting part. We will need a GitHub Actions pipeline that will build and deploy the DocC documentation to Cloudflare Pages. For this, we&#39;ll be using Cloudflare&#39;s <a href="https://github.com/cloudflare/wrangler-action">Wrangler Action</a>. To deploy from GitHub Actions, we will need to grab a Cloudflare API token. If you don&#39;t have a Cloudflare API token, you can grab one by following <a href="https://developers.cloudflare.com/workers/ci-cd/external-cicd/github-actions/#api-token">these steps</a>. This token should be set as a <code class="inline">CLOUDFLARE_API_TOKEN</code> in your GitHub repository&#39;s secrets.</p>
<p>
We&#39;ll use a <a href="https://github.com/cloudflare/wrangler-action?tab=readme-ov-file#deploy-when-commits-are-merged-to-main">Cloudflare example</a> as a base to build out our pipeline:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    name: Deploy
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}    </shiki-highlight>
  </div>
</div>
<p>
This pipeline will deploy the documentation to Cloudflare Pages every time you push to the <code class="inline">main</code> branch. You can adjust the <code class="inline">branches</code> field to match your repository&#39;s branch naming convention. However, we still need to build the documentation. If your package is buildable on Linux, we can keep the <code class="inline">ubuntu-latest</code> machine and we&#39;ll need to set up Swift:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
jobs:
  deploy:
    runs-on: ubuntu-latest
    name: Deploy
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
      - name: Setup Swift
        uses: SwiftyLab/setup-swift@latest    </shiki-highlight>
  </div>
</div>
<p>
If your package builds on macOS only, you can switch <code class="inline">ubuntu-latest</code> to <code class="inline">macos-latest</code> and remove the <code class="inline">Setup Swift</code> step.</p>
<p>
Before deploying, we&#39;ll reuse the step from the previous section to build the documentation and we&#39;ll update the deploy step to use the DocC artifacts:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
on:
  push:
    branches:
      - main

jobs:
  publish:
    runs-on: macos-latest
    name: Publish to Cloudflare Pages
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Build docs
        run: |
          swift package --allow-writing-to-directory .build/documentation generate-documentation --disable-indexing --output-path .build/documentation --transform-for-static-hosting --enable-experimental-combined-documentation --target YourProductA --target YourProductB
      - name: Deploy
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          # name-of-your-project is by default the name of the repository
          command: pages deploy .build/documentation --project-name=name-of-your-project    </shiki-highlight>
  </div>
</div>
<p>
...and that&#39;s it 🎉 Your DocC documentation will now be automatically built and deployed to Cloudflare Pages every time you push to the <code class="inline">main</code> branch. You can now enjoy your beautifully hosted documentation under your custom domain hosted on Cloudflare Pages.</p>
<p>
If you want to see how we use this setup in practice, check out the <a href="https://github.com/tuist/XcodeGraph">XcodeGraph</a> repository.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Debugging the communication between Xcode and XCBBuildService ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn how to debug the communication between Xcode and XCBBuildService with XCBLoggingBuildService. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/06/XCBLoggingBuildService"/>
      <id>https://tuist.dev/blog/2025/02/06/XCBLoggingBuildService</id>
      <updated>Thu, 06 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Xcode and <code class="inline">xcodebuild</code> use an internal service named <code class="inline">XCBBuildService</code> to perform build tasks. The contract between Xcode and <code class="inline">XCBBuildService</code> has been leveraged by some organizations, such as to proxy calls to other build systems like <a href="https://bazel.build">Bazel</a>. More recently, Apple has utilized it to add support for their new build system, <a href="https://github.com/swiftlang/swift-build">swift-build</a>, which we discussed in <a href="/blog/2025/02/03/swift-build">this blog post</a>.</p>
<p>
As a developer, this is generally not something you need to worry about. However, at Tuist, understanding this system has been on our backlog for some time, as we wanted to explore introducing optimizations and telemetry at a lower layer of the build process. The introduction of <code class="inline">swift-build</code> has shifted our focus, as it now makes more sense for us to explore that layer.</p>
<p>
While working with one of Tuist&#39;s customers, we observed some unusual behaviors, including Xcode projects and <code class="inline">xcodebuild</code> processes hanging, without a clear explanation. This prompted us to investigate the communication between Xcode and <code class="inline">XCBBuildService</code> and build a small utility to help debug it.</p>
<blockquote>
  <p>
XCBBuildService has been recently <a href="https://forums.swift.org/t/evolving-swiftpm-builds-with-swift-build/77596/23">open sourced</a> and rebranded as SWBBuildService.  </p>
</blockquote>
<h2 id="the-format" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Format<a href="#the-format" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Format"></a></h2>
<p>
Xcode spawns <code class="inline">XCBBuildService</code> as a system process and communicates with it through standard pipelines. Messages are formatted using <a href="https://msgpack.org/index.html">MessagePack</a>, a format similar to JSON but smaller and faster.</p>
<p>
The types of messages exchanged can be found in the Mobile Native Foundation&#39;s <a href="https://github.com/MobileNativeFoundation/XCBBuildServiceProxyKit/tree/main/Sources">XCBBuildServiceProxyKit</a> project or in the <a href="https://github.com/swiftlang/swift-build/tree/main/Sources/SWBProtocol"><code class="inline">SWBProtocol</code></a> target of <code class="inline">swift-build</code>. Among others, you will find messages for:</p>
<ul>
  <li>
Requesting indexing information  </li>
  <li>
Pinging the service  </li>
  <li>
Listing the available sessions (since multiple can exist)  </li>
  <li>
Starting a build operation  </li>
  <li>
Notifying about the completion of a build operation  </li>
</ul>
<p>
As mentioned earlier, you do not directly interact with these messages. Xcode and <code class="inline">xcodebuild</code>, acting as presentation layers, translate these internals into a debuggable UI or CLI output.</p>
<h2 id="debugging-messages-with-xcbloggingbuildservice" tabindex="-1" class="marketing__blog_post__body__content__heading">
Debugging Messages with XCBLoggingBuildService<a href="#debugging-messages-with-xcbloggingbuildservice" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Debugging Messages with XCBLoggingBuildService"></a></h2>
<p>
To facilitate debugging this communication, we built a new Swift package, <a href="https://github.com/tuist/XCBLoggingBuildService">XCBLoggingBuildService</a>. It serves as a simple wrapper around <code class="inline">XCBBuildService</code>, logging the messages exchanged between Xcode and the service.</p>
<p>
You can use it with Xcode or <code class="inline">xcodebuild</code> by following these steps:</p>
<p>
First, clone and build the project the repository:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
git clone https://github.com/tuist/XCBLoggingBuildService
swift build    </shiki-highlight>
  </div>
</div>
<p>
You can then use it with <strong>xcodebuild</strong> or <strong>Xcode</strong></p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# xcodebuild
XCBBUILDSERVICE_PATH=$(pwd)/.build/debug/XCBLoggingBuildService xcodebuild ...

# Xcode
env XCBBUILDSERVICE_PATH=$(pwd)/.build/debug/XCBLoggingBuildService /Applications/Xcode.app/Contents/MacOS/Xcode    </shiki-highlight>
  </div>
</div>
<p>
The logs are saved in /tmp/XCBLoggingBuildService.log. You can monitor them in real time using:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tail -f /tmp/XCBLoggingBuildService.log    </shiki-highlight>
  </div>
</div>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
In the coming months, we&#39;ll explore the internals of swift-build, its extensibility, and the capabilities it offers for Tuist to optimize your projects and enhance telemetry for better decision-making. Of course, we&#39;ll document our learnings in this blog.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ A Mise guide for Swift developers ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we share how to use Mise to install, activate, and share tools to enhance Swift development. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/04/mise"/>
      <id>https://tuist.dev/blog/2025/02/04/mise</id>
      <updated>Tue, 04 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When building with Swift, <a href="https://apple.com">Apple</a> provides a comprehensive toolchain through the <a href="https://developer.apple.com/xcode/">Xcode</a> installation. Running <code class="inline">swift run</code> seamlessly builds and executes your code using the Swift compiler, eliminating concerns about the underlying toolchain. However, additional tools like <a href="https://github.com/nicklockwood/SwiftFormat">SwiftFormat</a> or <a href="https://github.com/apple/swift-openapi-generator">swift-openapi-generator</a> may be required. These tools need to be installed on your system, raising the question of how to manage their installation—not only for developers&#39; environments but also for CI/CD pipelines. In this blog post, we’d like to introduce you to <a href="https://github.com/jdx/mise">Mise</a>, a tool that not only addresses the installation and distribution of tools but also ensures they are activated deterministically so that everyone is using the same version of the tools.</p>
<h2 id="what-is-mise?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is Mise?<a href="#what-is-mise?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is Mise?"></a></h2>
<p>
Mise is a front-end for your development environment.  <br>
Okay, that might sound abstract, but if we talk about the problems it solves, it becomes clearer.  <br>
Almost every project has:</p>
<ol>
  <li>
A set of tools it depends on.  </li>
  <li>
A set of scripts to interact with the project from the terminal.  </li>
  <li>
Environment variables to configure the interaction with the project.  </li>
</ol>
<p>
Traditionally, developers address the first point with <a href="https://brew.sh">Homebrew</a>, telling developers in the <code class="inline">README.md</code> file what additional tools need to be installed. However, this approach is not ideal. First, it’s manual, and second, there’s no mechanism to ensure the presence of not only the tools but <strong>the right version of the tools</strong>. The second point is usually handled with <code class="inline">Makefiles</code>, custom bash scripts, Ruby scripts run by <a href="https://fastlane.tools">Fastlane</a>, or a mix of everything. If Fastlane is the tool, it requires developers to have Ruby installed, along with the Ruby dependencies (i.e., <code class="inline">gems</code>) installed via <code class="inline">bundle install</code>. Do you start to notice the amount of indirection? As for the third point, which is less common, it’s usually addressed by instructing developers in the README to introduce project state into a global environment, which is generally not a good idea.</p>
<p>
Now, imagine simplifying all of the above to just one command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mise install    </shiki-highlight>
  </div>
</div>
<p>
Well, that’s what a front-end for your development environment is all about. Now that we’ve understood what Mise is, let’s walk through some of its features and how they can be valuable in the context of app development with Swift. Before continuing, make sure you have Mise installed on your system. You can install it by following <a href="https://mise.jdx.dev/getting-started.htm">these steps</a>.</p>
<h2 id="dev-tools" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dev tools<a href="#dev-tools" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dev tools"></a></h2>
<p>
The first and most core feature of Mise is the ability to install and activate <a href="https://mise.jdx.dev/dev-tools/">dev tools</a>. Note that we say &quot;activate&quot; because, unlike Homebrew, Mise differentiates between installing a tool and making a specific version of it available. Thanks to this, you have control over which version of the tool is activated—either globally or scoped to a particular project. For example, let’s say we have a project that uses SwiftFormat, SwiftLint, and Tuist. We can create a mise.toml file with the following content:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[tools]
tuist = &quot;4.39.1&quot;
swiftlint = &quot;0.54.0&quot;
swiftformat = &quot;0.53.3&quot;    </shiki-highlight>
  </div>
</div>
<p>
Then, run <code class="inline">mise install</code>. This command will not only install the tools but also activate those specific versions. If you run <code class="inline">swiftlint --version</code>, you’ll see that it’s using the version specified in the <code class="inline">mise.toml</code> file. This might seem like a subtle detail, but inconsistent versions across environments are often a common source of wasted time debugging issues.</p>
<h3 id="backends" tabindex="-1" class="marketing__blog_post__body__content__heading">
Backends<a href="#backends" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Backends"></a></h3>
<p>
&quot;How&quot; to install a specific dev tool is determined by what Mise calls &quot;backends.&quot; By default, Mise tries to use the <a href="https://asdf-vm.com/">asdf</a> backend. asdf is another developer tool for installing developer tools, and the installation logic for each tool is declared in what they call plugins. For example, in the case of SwiftLint, there’s an <a href="https://github.com/mise-plugins/mise-swiftlint">official plugin</a> that declares how to install SwiftLint.</p>
<p>
But what if you want to depend on a Swift CLI contained in a repository that doesn’t have a plugin? Well, there’s the <a href="https://mise.jdx.dev/dev-tools/backends/spm.html">SwiftPM</a> backend. In other words, Mise knows how to install it automatically without needing a plugin or a script that instructs Tuist on how to do so. If you’re familiar with <a href="https://github.com/yonaskolb/Mint">Mint</a>, think of the SwiftPM backend of Mise as Mint. The amazing thing about Mise is that you don’t need a tool per language or technology. You can use one tool to rule them all. In your <code class="inline">mise.toml</code>, you could declare the tool like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[tools]
&quot;spm:owner/repo&quot; = &quot;latest&quot;    </shiki-highlight>
  </div>
</div>
<blockquote>
  <p>
The backend will compile the CLI on the host, which may take some time and potentially fail if the required toolchain is not present. Therefore, it’s always recommended to provide binaries. However, as long as your CLI is not that big, this is a good way to get started.  </p>
</blockquote>
<p>
Thanks to the dev tools in the <code class="inline">mise.toml</code>, you no longer need a lengthy list of steps in the README telling developers which tools they need to install.</p>
<h2 id="hooks" tabindex="-1" class="marketing__blog_post__body__content__heading">
Hooks<a href="#hooks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Hooks"></a></h2>
<p>
Let’s now talk about <a href="https://mise.jdx.dev/hooks.html">hooks</a>. Some projects might require additional steps beyond installing tools. For example, if you’re using Tuist, you might need to run <code class="inline">tuist install</code>, or if you’re using Fastlane, you might need to run <code class="inline">bundle install</code> to install the Ruby dependencies. Mise allows you to define hooks that can run at certain moments, such as when cd-ing into a directory or after running <code class="inline">mise install</code>. The latter is particularly useful in the context of app development because it’s the place where we could install Ruby dependencies and SPM packages:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[hooks]
postinstall = [
  &#39;bundle install&#39;,
  &#39;tuist install&#39;
]    </shiki-highlight>
  </div>
</div>
<h2 id="environment-variables" tabindex="-1" class="marketing__blog_post__body__content__heading">
Environment variables<a href="#environment-variables" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Environment variables"></a></h2>
<p>
Mise also allows activating environment variables and secrets when entering a particular project. Unlike other ecosystems, using environment variables to configure Xcode behaviors is not that common. However, there’s a capability in Mise that can be quite useful in improving the ergonomics of your automation: Mise allows configuring the <code class="inline">PATH</code> environment variable, which is used by the system to resolve executables. Why is that useful? You might wonder. Well, if you’re a Fastlane user and are a bit tired of having to prefix your commands with <code class="inline">bundle exec</code>, you can use the following Mise configuration:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
toml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="toml">
[tools]
ruby = &quot;3.4.1&quot;

[hooks]
postinstall = [
  &#39;bundle install --binstubs=.bundlestubs&#39;,
]

[env]
_.path = [&quot;.bundlestubs&quot;]    </shiki-highlight>
  </div>
</div>
<h2 id="tasks" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tasks<a href="#tasks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tasks"></a></h2>
<p>
Tasks are the last feature we’d like to talk about. At Tuist, we use them extensively across our repositories. Think of them as language-agnostic Fastlane lanes or Makefiles with superpowers. Tasks are scripts that you can invoke with <code class="inline">mise run</code>. They can be defined in the <a href="https://mise.jdx.dev/tasks/toml-tasks.html"><code class="inline">mise.toml</code> file</a> or in <a href="https://mise.jdx.dev/tasks/file-tasks.html">files</a> following a conventional structure that’s then used to construct the full command name. We lean on using files to keep the configuration file tidy. For example, let’s say you’d like to have a task, build, to <code class="inline">build</code> the scheme <code class="inline">MyApp</code> of your project. You can create a file at <code class="inline">.mise/tasks/build.sh</code> with the following content:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
#!/usr/bin/env bash
#MISE description=&quot;Build MyApp&quot;
#MISE alias=&quot;b&quot;
#USAGE flag &quot;-n --no-signing&quot; help=&quot;Disable the signing&quot;

if [ &quot;$usage_no_signing&quot; = &quot;true&quot; ]; then
  xcodebuild -scheme MyApp -workspace $MISE_PROJECT_ROOT/MyApp.xcworkspace clean build CODE_SIGN_IDENTITY=&quot;&quot; CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
else
  xcodebuild -scheme MyApp -workspace $MISE_PROJECT_ROOT/MyApp.xcworkspace clean build
fi    </shiki-highlight>
  </div>
</div>
<p>
You can run it with <code class="inline">mise run build</code>, or more interactively, run <code class="inline">mise run</code> and then select the task you want to run from the terminal. Cool, isn’t it?</p>
<p>
There’s a lot to parse in the above script. Did you notice those annotations under the <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">shebang</a>? They are annotations used by Mise to provide extra capabilities. The description is used by Mise to show the description alongside the task name when listing the tasks, making it easy to recognize what the task does. You can also define aliases for the task. In the case above, we defined the alias <code class="inline">b</code>, which allows running <code class="inline">mise run b</code>. Last but not least, one of our favorites: the USAGE annotation. Usage is a <a href="https://usage.jdx.dev">specification</a> to declare the interface of a CLI. Thanks to having a standard specification, it can be codified using comments, which Mise will use to parse and validate arguments for you, and then provide you with the values as environment variables. Thanks to that, we can turn our scripts into mini CLIs without having to include parsing and validation logic in the scripts:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mise run build --no-signing    </shiki-highlight>
  </div>
</div>
<p>
Note that we wrote the above script in bash, but you could have chosen your language of choice, such as Ruby. By adding the tool to the <code class="inline">mise.toml</code> and updating the shebang to <code class="inline">!#/usr/bin/env ruby</code>, you can have the peace of mind that everyone will be able to run the script because Mise will take care of installing the right version of Ruby.</p>
<h2 id="some-closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Some closing words<a href="#some-closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Some closing words"></a></h2>
<p>
We think Mise is amazing. It’s a love letter to automation.
When we gave it a try for the first time, we didn’t think twice about embracing it as one of our installation methods and making Tuist play an evangelist role in the Swift ecosystem.
We recommend giving it a try in your projects and experimenting with it across local and CI environments.
We bet you’ll find it as useful as we did.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ What Swift Build means for the Swift ecosystem ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In blog post we share our perspective on what Swift Build might mean for the Swift ecosystem, drawing from our extensive experience working with Xcode projects, and how it aligns with the plans we have for Tuist. ]]></summary>
      <link href="https://tuist.dev/blog/2025/02/03/swift-build"/>
      <id>https://tuist.dev/blog/2025/02/03/swift-build</id>
      <updated>Mon, 03 Feb 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
With the introduction of <a href="https://www.swift.org/getting-started/">Swift</a>, it became clear that Apple wanted the language to run everywhere. In the years that followed, we witnessed various initiatives aligned with that vision, such as frameworks like <a href="https://vapor.codes">Vapor</a> enabling Swift to run on servers and support for compiling <a href="https://www.swift.org/blog/embedded-swift-examples/">Swift for embedded devices</a>. At the same time, this presented Apple with an interesting challenge: reconciling a world designed for Apple platforms with one where Apple is just one of many supported platforms.</p>
<p>
This reconciliation effort had to happen at various levels, from frameworks to tooling. You might have seen Apple’s initiative to open-source <a href="https://github.com/swiftlang/swift-foundation">Foundation</a>. Foundation is so <em>&quot;foundational&quot;</em> to crafting software in Swift that Apple decided to decouple it from Apple platforms and make it open source.</p>
<p>
One of the reconciliation layers that took longer to receive attention is the build system. With the recent announcement of <a href="https://www.swift.org/blog/the-next-chapter-in-swift-build-technologies/">Swift Build</a>, Apple has signaled that this is finally changing.</p>
<p>
In this blog post, we’d like to provide our perspective into what this might mean for the ecosystem, drawing from our extensive experience working with Xcode projects, and how it aligns with the plans we have for Tuist. But first, let’s talk about build systems.</p>
<h2 id="build-systems" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build Systems<a href="#build-systems" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build Systems"></a></h2>
<p>
A build system is software responsible for producing runnable or shareable software artifacts, such as a static library or a macOS app. Every modern programming language comes with a build system, typically integrated with other tools like test runners, formatters, or dependency managers. <a href="https://www.rust-lang.org">Rust</a> has <a href="https://doc.rust-lang.org/cargo/">Cargo</a>, <a href="https://elixir-lang.org">Elixir</a> has <a href="https://hexdocs.pm/mix/Mix.html">Mix</a>, and <a href="https://go.dev">Go</a> has its <code class="inline">go</code> tool. In the Apple ecosystem, we have two: <code class="inline">xcodebuild</code> and <a href="https://github.com/swiftlang/swift-package-manager">SwiftPM</a>. This duality exists as a consequence of reconciling two worlds.</p>
<p>
Build systems require a representation of a project, which can be codified in the build system using conventions, serializable configuration files like <code class="inline">Cargo.toml</code>, or a mix of both. In the case of <code class="inline">xcodebuild</code> and SwiftPM, projects are represented in the hardly-serializable <code class="inline">.pbxproj</code> format and <code class="inline">Package.swift</code> files, respectively.</p>
<p>
<strong>Build tools construct an in-memory representation of projects</strong>, typically resembling a graph. With this graph in memory, the build system can not only compile the project but also analyze it, optimize it, or even provide a foundation for coding experiences like <a href="https://en.wikipedia.org/wiki/Language_Server_Protocol">language server protocols</a> (LSPs).</p>
<p>
In the Swift ecosystem, we’ve long had two graphs with significant overlap: one generic enough to work across many operating systems, and another tightly coupled to Apple’s OSs and Xcode. This resulted in duplicated efforts and challenges in delivering a great developer experience (DX). For years, the ecosystem suffered from features that either didn’t work, worked unreliably, or were simply slow.</p>
<h2 id="a-unified-graph" tabindex="-1" class="marketing__blog_post__body__content__heading">
A unified graph<a href="#a-unified-graph" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A unified graph"></a></h2>
<p>
With <a href="https://github.com/swiftlang/swift-build">Swift Build</a>, Apple is unifying the build system and the graph used by both SwiftPM and Xcode. If the toolchain is a stack of layers, with the build system sitting at the bottom of SwiftPM and Xcode, this unification is akin to pushing that layer down to share it across both tools. We think this is a great idea.</p>
<p>
Note that the formats remain different—on one side, you have Swift packages, and on the other, Xcode projects. These are converted into a Project Interchange Format (PIF) before being passed to the build system.</p>
<h2 id="the-impact-on-developer-experience" tabindex="-1" class="marketing__blog_post__body__content__heading">
The impact on developer experience<a href="#the-impact-on-developer-experience" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The impact on developer experience"></a></h2>
<p>
This unification will take time to fully materialize, but once it does, we believe the improvements to the developer experience will be unprecedented:</p>
<ul>
  <li>
<strong>Faster rollout of improvements</strong>: New features and improvements will only need to be implemented once, speeding up their availability.  </li>
  <li>
<strong>Increased reliability</strong>: Eliminating part of the reconciliation challenge should result in more reliable features, such as build determinism or SwiftUI previews.  </li>
  <li>
<strong>Extensibility</strong>: The new build system is designed to be extensible, making it easier for the community to add support for new platforms without directly contributing to the build system repository. Imagine selecting WebAssembly as a build destination directly from Xcode’s UI.  </li>
  <li>
<strong>Build-time optimizations</strong>: Apple is taking the opportunity to enable build-time optimizations similar to Bazel. Explicit modules were the first step in this direction, and the presence of a <a href="https://en.wikipedia.org/wiki/Content-addressable_storage">CAS (Content Addressable Storage)</a> in the codebase suggests more optimizations are on the horizon.  </li>
  <li>
<strong>Foundation for new coding experiences</strong>: This unified build system can serve as a foundation for innovative coding experiences, pushing the boundaries of what’s possible in Xcode. AI is already proving that letting the market or ecosystem explore new ideas can be a catalyst for innovation.  </li>
</ul>
<p>
We strongly recommend trying Swift Build in your projects and reporting any issues you encounter. Your feedback will help Apple refine this new foundation into something truly incredible.</p>
<h2 id="how-it-relates-to-our-plans" tabindex="-1" class="marketing__blog_post__body__content__heading">
How it relates to our plans<a href="#how-it-relates-to-our-plans" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How it relates to our plans"></a></h2>
<p>
Tuist aims to improve the experience of building apps by extending Apple’s toolchain. An extensible foundation is something we’re very excited about because it unlocks new opportunities that feel more mature and aligned with the platform.</p>
<p>
While the foundation provides all the information needed to understand and optimize projects, improving projects often requires a more holistic view of the data—how it evolves over time and how it connects to work happening in places like GitHub. That’s where our strength lies. We bring the server infrastructure, standardize the data, make it accessible to you, and build useful server features on top of it. This allows you to focus on checking out the code and building your apps with Xcode—or maybe Cursor in the future.</p>
<p>
Reverse-engineering the internals of Xcode’s build system or Xcode projects is something we’ve done for many years. The possibility of not having to do that anymore is amazing because <strong>it frees up our creative energy to focus on other areas while supporting Apple in evolving this new open foundation.</strong></p>
<h2 id="the-overlap-between-swift-packages-and-xcode-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
The overlap between Swift Packages and Xcode Projects<a href="#the-overlap-between-swift-packages-and-xcode-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The overlap between Swift Packages and Xcode Projects"></a></h2>
<p>
You might have noticed that while the build system is being unified, there are still two formats with some overlap: Xcode projects and Swift packages. The former has its flaws, which have allowed us to build a thriving community at Tuist around generated projects. The latter is being used by many teams to address the shortcomings of Xcode projects. However, because Swift packages were never designed for this purpose, the developer experience starts to suffer at scale.</p>
<p>
What will the future look like? It’s uncertain, but we doubt we’ll have two formats forever. Like <code class="inline">xcodebuild</code>, the Xcode project format was designed for Apple platforms and has accumulated a lot of legacy over the years, making it a nightmare to maintain at scale. On the other hand, Swift packages, where manifests need to be compiled and can easily introduce side effects, don’t seem ideal either—at least not without significant changes.</p>
<p>
Perhaps we’ll see a Swift Build DSL, similar to Gradle’s <a href="https://docs.gradle.org/current/userguide/kotlin_dsl.html">Kotlin DSL</a>, specifically designed for declaring build graphs without side effects. This DSL could be evaluated so that changes in it translate to graph changes almost instantly, Or who knows... perhaps <a href="https://github.com/apple/pkl">PKL</a> becomes the language. Regardless of the path, we at Tuist would love to see this developed in the open and would even like to take part in it if possible. We have many ideas from our experience understanding and optimizing Xcode projects that we’d love to contribute to the ecosystem.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
This is a move worth celebrating. Every new component that Apple makes open source is an opportunity for diverse ideas to emerge and for the entire ecosystem to improve. So, thank you to everyone who made this possible. We couldn’t be more excited about it, and we’re eager to see what the future holds for Swift.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Announcing Tuist Registry ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We're thrilled to announce the launch of the Tuist Registry – a new feature that optimizes the resolution of Swift packages in your projects. ]]></summary>
      <link href="https://tuist.dev/blog/2025/01/22/announcing-tuist-registry"/>
      <id>https://tuist.dev/blog/2025/01/22/announcing-tuist-registry</id>
      <updated>Wed, 22 Jan 2025 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
  <img src="/marketing/images/blog/2025/01/22/announcing-tuist-registry/registry-illustration.png" alt="Tuist Registry illustration">
</p>
<p>
Tuist Registry is a new feature that optimizes the resolution of Swift packages in your projects. Gone are the days when you had to install the full git history of any package you wanted to use – instead, Tuist Registry, built on top of the <a href="https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md">Swift Package Registry</a> standard, allows you to download only source archives of the package versions you need – saving both time and disk space, locally or on the CI, and making the resolution more deterministic and reliable. The Tuist Registry mirrors the <a href="https://swiftpackageindex.com/">Swift Package Index</a> and is available for any open source Swift package in the community – served from a global storage for low latency.</p>
<p>
If you prefer to watch a video to learn more about the Tuist Registry, you can watch the following Tuist Registry walkthrough video:</p>
<iframe title="Tuist Registry Walkthrough" width="560" height="315" src="https://videos.tuist.dev/videos/embed/2bd2deb4-1897-4c5b-9de6-37c8acd16fb0" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="swift-package-registry" tabindex="-1" class="marketing__blog_post__body__content__heading">
Swift Package Registry<a href="#swift-package-registry" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Swift Package Registry"></a></h2>
<p>
The Swift Package Manager has become the de-facto standard for managing dependencies in Swift projects. However, unlike some other package managers like <a href="https://cocoapods.org/">Cocoapods</a> or <a href="https://www.npmjs.com/">npm</a>, SwiftPM does not have a central registry for packages. Instead, it relies on the package&#39;s source repository to host the package. While it does mean there&#39;s no need for a central authority for publishing and downloading packages, it also means there are some inefficiencies in how packages are resolved.</p>
<p>
When you add a package to your project, SwiftPM needs to do a deep clone of <em>any</em> Swift package you want to use. This can take a long time to download and consume a lot of disk space, especially for projects with large git history. For example, a well-known app that moved to the registry reported that the disk space consumed by the registry resolution was <strong>91 % smaller</strong> – going from 6.6 GB to 600 MB. The time to restore and save the cached dependencies on the CI, something done on every run, dropped accordingly from 2 minutes to just 20 s. </p>
<p>
Apart from the performance and efficiency improvements, depending on the Git history and tags can lead to non-deterministic builds and potential security issues since the Git history is not immutable.</p>
<p>
Luckily, SwiftPM now has the capability to centralize the resolution of packages thanks to <a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md">the Package Registry Service evolution proposal SE-0292</a>, which aims at addressing the following challenges:</p>
<ul>
  <li>
<strong>Reproducibility</strong>: A version tag in the Git repository for a dependency can be reassigned to another commit at any time. This can cause a project to produce different build results depending on when it was built.  </li>
  <li>
<strong>Availability</strong>: The Git repository for a dependency can be moved or deleted, which can cause subsequent builds to fail.  </li>
  <li>
<strong>Efficiency</strong>: Cloning the Git repository for a dependency downloads all versions of a package when only one is used at a time.  </li>
  <li>
<strong>Speed</strong>: Cloning a Git repository for a dependency can be slow if it has a large history. Also, cloning a Git repository is expensive for both the server and client, and may be significantly slower than downloading the same content using HTTP through a content delivery network (CDN).  </li>
</ul>
<p>
While the registry has been used by some to allow organizations to distribute private packages through their internal registry, the usage to improve efficiency and developers&#39; productivity remained unexplored until today.</p>
<h2 id="security" tabindex="-1" class="marketing__blog_post__body__content__heading">
Security<a href="#security" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Security"></a></h2>
<p>
We take security very seriously at Tuist and the Tuist Registry is no exception. For a centralized registry, security is paramount. There are a couple of security measures that we have implemented to ensure the security of the packages in the registry:</p>
<ul>
  <li>
We only sync packages available in the <a href="https://swiftpackageindex.com/">Swift Package Index</a>.  </li>
  <li>
Sources are always pulled directly from the original package repository.  </li>
  <li>
The <code class="inline">swift</code> CLI always verifies the downloaded package source archive checksums against the checksums provided by the registry.  </li>
</ul>
<p>
Additionally, we&#39;re in the process of obtaining the <a href="https://secureframe.com/hub/soc-2/what-is-soc-2">SOC 2</a> certification to have a formal verification that our security practices are up to the highest standards. If you have questions around the security, shoot us an email at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a> and we&#39;ll be happy to answer them.</p>
<h2 id="get-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Get started<a href="#get-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Get started"></a></h2>
<p>
The Tuist Registry implements the Swift Package Registry standard and is thus compatible with any SwiftPM setup that you might have – regardless whether you use Tuist Generated Projects or not.</p>
<p>
To start using the registry, first <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist#install-tuist">install Tuist</a>. Then you need to have a <a href="https://docs.tuist.dev/en/server/introduction/accounts-and-projects">Tuist Project</a>. You can create one by running:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist auth login
# Obtain your account handle by running `tuist auth whoami`
tuist project create {your-account-handle}/{your-project-handle}    </shiki-highlight>
  </div>
</div>
<p>
Additionally, you need to create a <code class="inline">Tuist.swift</code> file in the root of your project with the following content:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let tuist = Tuist(
    fullHandle: &quot;{your-account-handle}/{your-project-handle}&quot;
)    </shiki-highlight>
  </div>
</div>
<p>
Afterwards, you need to run the following commands to enable the Tuist Registry:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Generates a registry configuration in your project
tuist registry setup
# Creates and stores credentials to access the registry
tuist registry login    </shiki-highlight>
  </div>
</div>
<p>
...and you&#39;re done!</p>
<p>
<code class="inline">tuist registry setup</code> automatically configures your project to use the Tuist Registry. When adding a package through the Xcode UI, you will now see the Tuist Registry as an option to resolve the package from (note the <code class="inline">tuist.dev</code> registry in the top right corner):</p>
<p>
  <img src="/marketing/images/blog/2025/01/22/announcing-tuist-registry/registry-add-package.png" alt="Adding package with the Tuist Registry">
</p>
<p>
To learn more about the Tuist Registry, head over to our <a href="https://docs.tuist.dev/en/guides/develop/registry">documentation</a>.</p>
<h2 id="building-a-low-latency-registry-for-open-source-packages" tabindex="-1" class="marketing__blog_post__body__content__heading">
Building a low-latency registry for open source packages<a href="#building-a-low-latency-registry-for-open-source-packages" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Building a low-latency registry for open source packages"></a></h2>
<p>
We implemented an API that complies with the specification to serve releases of all the packages listed at <a href="https://swiftpackageindex.com/">Swift Package Index</a>, the default directory of community packages. Unlike decentralized resolution, developers get just the source code of every package version and do so from a global storage network that serves them with as minimum latency as possible. At the time of writing, we serve around 8.4K packages and 130k releases – and that number is growing every day.</p>
<p>
When implementing the Tuist Registry, there were a couple of bugs that we found in the SwiftPM registry implementation. To fix these for anyone using the Swift Package Registry, we submitted the following PRs:</p>
<ul>
  <li>
<a href="https://github.com/swiftlang/swift-package-manager/pull/8166">Fix resolve failing when package from registry is referenced by name</a>  </li>
  <li>
<a href="https://github.com/swiftlang/swift-package-manager/pull/8188">Fix registry resolution of major alternate package manifests</a>  </li>
  <li>
<a href="https://github.com/swiftlang/swift-package-manager/pull/8194">Fix registry package swizzling when package name casing differs</a>  </li>
</ul>
<p>
All of these PRs have been merged and should be available as part of the next Swift 6.1 release. However, until then, we have fixed these issues in the <code class="inline">Package.swift</code> manifests when uploading a package to our registry. We plan to remove these workarounds when Swift 6.1 is used by the majority of the community.</p>
<p>
Additionally, we also posted a <a href="https://github.com/swiftlang/swift-package-manager/pull/8220">PR</a> to parallelize retrieving packages – both when using source control and registry resolution. Once this PR is merged and released, the SwiftPM clean resolution should be up to <em>2x faster</em>. For <em>anyone</em>. We love to give back to the community and make the whole Swift ecosystem better for everyone.</p>
<h2 id="love-letter-to-the-community" tabindex="-1" class="marketing__blog_post__body__content__heading">
Love letter to the community<a href="#love-letter-to-the-community" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Love letter to the community"></a></h2>
<p>
The Tuist Registry is our love letter to the Swift community. It wouldn&#39;t have been possible without all the amazing work that the community has done. We&#39;re excited to see how the community will embrace the registry and how it will help to make Swift projects more efficient and reliable.</p>
<p>
And always, feedback is welcome – if you have any suggestions or ideas on how to improve the registry, please let us know on our <a href="https://community.tuist.dev/">community forum</a> or on <a href="https://github.com/tuist/tuist">our GitHub</a>. We&#39;re looking forward to hearing from you!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ The ultimate guide to signing CLIs for macOS (Darwin) ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we'll go through the process of signing a CLI for macOS (Darwin). ]]></summary>
      <link href="https://tuist.dev/blog/2024/12/31/signing-macos-clis"/>
      <id>https://tuist.dev/blog/2024/12/31/signing-macos-clis</id>
      <updated>Tue, 31 Dec 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
You&#39;ve built a portable CLI in a programming language like <a href="https://ziglang.org/">Zig</a>, <a href="https://www.rust-lang.org/">Rust</a>, <a href="https://go.dev/">Go</a>, or <a href="https://www.swift.org/">Swift</a>. Through continuous integration you build binaries for the various supported platforms and architectures, and through a bash script or any other installation method, you make it easier for users to install it. However, after users install it and try to open it, they get an error: <code class="inline">&quot;&#39;your-cli&#39; can&#39;t be opened because Apple cannot check it for malicious software.&quot;</code>.</p>
<p>
This error occurs because macOS has a security feature called Gatekeeper, which is designed to ensure that only trusted software runs on the system. When you try to open your CLI, Gatekeeper checks if the software has been signed and notarized by Apple. If it hasn&#39;t, macOS will block it from running, displaying the error message mentioned above.</p>
<blockquote>
  <p>
Homebrew, a popular package manager for macOS, attempts to apply an ad-hoc signature to the file using <a href="https://github.com/Homebrew/brew/blob/eac5720d44457fcfcb24b325bde3a70fce41ac15/Library/Homebrew/extend/os/mac/keg.rb#L40"><code class="inline">codesign --sign -</code></a> to prevent this error from happening. However, we recommend you sign it with your own identity to ensure that the software is from a verified source.  </p>
</blockquote>
<p>
All the code examples in this blog post are available in <a href="https://gist.github.com/tuistit/0e756d7eb5a707d7b215ef4aa8d072d9">this gist</a>.</p>
<h2 id="what-is-code-signing?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is code signing?<a href="#what-is-code-signing?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is code signing?"></a></h2>
<p>
Code signing is the process of digitally signing executables and scripts to confirm the software author and <strong>guarantee that the code has not been altered or corrupted since it was signed.</strong> This is done using a cryptographic hash to validate the integrity and authenticity of the software. By signing your CLI, you provide a level of trust to the users and the operating system that the software is from a verified source and has not been tampered with.</p>
<h2 id="what-is-notarization?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is notarization?<a href="#what-is-notarization?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is notarization?"></a></h2>
<p>
Notarization is an additional layer of security provided by Apple. After signing your software, you can submit it to Apple for notarization. Apple will scan your software for malicious content and, if it passes the checks, will issue a notarization ticket. This ticket is then attached to your software, indicating that it has been verified by Apple and is safe to run on macOS. Notarization helps to <strong>reassure users that the software is trustworthy and complies with Apple&#39;s security standards.</strong></p>
<p>
By signing and notarizing your CLI, you ensure that it can be opened and run on macOS without triggering security warnings, providing a smoother and more secure experience for your users. </p>
<h2 id="prerequisites" tabindex="-1" class="marketing__blog_post__body__content__heading">
Prerequisites<a href="#prerequisites" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Prerequisites"></a></h2>
<p>
To sign and notarize your CLI, you&#39;ll need:</p>
<ul>
  <li>
A <a href="https://developer.apple.com/">developer account</a>, which at the time of this writing costs $99 per year.  </li>
  <li>
An <a href="https://support.apple.com/en-us/102654">app-specific password</a> for your Apple ID.  </li>
  <li>
A macOS environment with the Xcode <a href="https://developer.apple.com/xcode/resources/">developer tools</a> installed. Alternatively, you can use <a href="https://crates.io/crates/apple-codesign">apple-codesign</a>, which is a Rust crate that provides a CLI for signing and notarizing Apple artifcats from Linux environments.  </li>
</ul>
<h2 id="create-a-'developer-id-application'-certificate" tabindex="-1" class="marketing__blog_post__body__content__heading">
Create a &#39;Developer ID Application&#39; certificate<a href="#create-a-'developer-id-application'-certificate" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Create a 'Developer ID Application' certificate"></a></h2>
<p>
The first step is to create a &#39;Developer ID Application&#39; certificate. You can head to the the <a href="https://developer.apple.com/account/resources/certificates/list">certificates</a> page and click on the &#39;Create a Certificate&#39; button. Check the &#39;Developer ID Application&#39; option and click on the &#39;Continue&#39; button. To proceed, you&#39;ll need to generate a <a href="https://developer.apple.com/help/account/create-certificates/create-a-certificate-signing-request">certificate signing request (CSR)</a> and upload it. Once you&#39;ve done that, you&#39;ll be able to download the certificate and install it in your local <a href="https://support.apple.com/guide/keychain-access/what-is-keychain-access-kyca1083/mac">keychain</a> by double-clicking on it.</p>
<p>
Select the filtering option &#39;My Certificates&#39; to ensure for each certificate you see the private key associated with it in a dropdown menu (screenshot below).</p>
<p>
  <img src="/marketing/images/blog/2024/12/31/signing-macos-clis/keychain.png" alt="A screenshot that shows the keychain and the &#39;Developer ID Application&#39; certificate in the list">
</p>
<h2 id="sign-the-cli" tabindex="-1" class="marketing__blog_post__body__content__heading">
Sign the CLI<a href="#sign-the-cli" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Sign the CLI"></a></h2>
<p>
Once you have the pair of certificates, you can sign your CLI with the following command. <code class="inline">$CERTIFICATE_NAME</code> is the name of the certificate you want to use to sign your CLI, which you can find in the keychain:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
CERTIFICATE_NAME=&quot;Developer ID Application: Tuist GmbH (U6LC622NKF)&quot;
/usr/bin/codesign --sign &quot;$CERTIFICATE_NAME&quot; --timestamp --options runtime --verbose /path/to/your/cli    </shiki-highlight>
  </div>
</div>
<h2 id="notarize-the-cli" tabindex="-1" class="marketing__blog_post__body__content__heading">
Notarize the CLI<a href="#notarize-the-cli" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Notarize the CLI"></a></h2>
<p>
To notarize your CLI, you&#39;ll first need to zip the CLI binary:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
zip -q -r --symlinks &quot;notarization-bundle.zip&quot; your-cli    </shiki-highlight>
  </div>
</div>
<p>
And then upload it to the notarization service through their API:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
TEAM_ID=&quot;U6LC622NKF&quot;
APPLE_ID=&quot;...&quot;
APP_SPECIFIC_PASSWORD=&quot;...&quot;
RAW_JSON=$(xcrun notarytool submit &quot;notarization-bundle.zip&quot; \
    --wait \
    --apple-id &quot;$APPLE_ID&quot; \
    --team-id &quot;$TEAM_ID&quot; \
    --password &quot;$APP_SPECIFIC_PASSWORD&quot; \
    --output-format json)
echo &quot;$RAW_JSON&quot;
SUBMISSION_ID=$(echo &quot;$RAW_JSON&quot; | jq -r &#39;.id&#39;)
echo &quot;Notarized with submission id: $SUBMISSION_ID&quot;    </shiki-highlight>
  </div>
</div>
<p>
Once the submission is accepted, your CLI should be ready to be distributed to the users.</p>
<blockquote>
  <p>
Apple&#39;s documentation recommends to staple the notarization ticket to the binary. However, this doesn&#39;t work with standalone binaries, but since it&#39;s not mandatory, you can skip it.  </p>
</blockquote>
<h2 id="signing-from-non-interactive-environments-(ci)" tabindex="-1" class="marketing__blog_post__body__content__heading">
Signing from non-interactive environments (CI)<a href="#signing-from-non-interactive-environments-(ci)" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Signing from non-interactive environments (CI)"></a></h2>
<p>
Signing from a local environment is the easy part.
However, when signing from a CI environment,
there are a few things that you need to take into account to ensure that the signing process is successful.
Many organizations and developers prefer to use <a href="https://docs.fastlane.tools/actions/match/">Fastlane Match</a>,
which abstracts those intricacies away. But it&#39;s not as intricate as people think, so we are going to share how you can do it with a bash script.</p>
<h3 id="exporting-the-certificate-and-private-key" tabindex="-1" class="marketing__blog_post__body__content__heading">
Exporting the certificate and private key<a href="#exporting-the-certificate-and-private-key" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Exporting the certificate and private key"></a></h3>
<p>
To sign from other environments, you&#39;ll have to export the certificate and the private key that you generated. It&#39;s crucial that you export the private key as well since it&#39;s required to sign the CLI. It&#39;s something that&#39;s easy to do wrong, so make sure when exporting that you&#39;ve selected &#39;My Certificates&#39; in the keychain, and for each entry, you can see both the certificate and the private key. Then right-click on the certificate and export it as a <code class="inline">.p12</code> file.
We recommend setting a password for the <code class="inline">.p12</code> file to add an extra layer of security. Store the password in a secure place, and make sure that the CI environment has access to it.</p>
<p>
You can then turn it into base64 to expose it as an environment variable in the CI environment (e.g. <code class="inline">BASE_64_CERTIFICATE</code>). Alternatively, you can keep it encrypted in the repository and decrypt it in the CI environment:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
base64 -i ~/path/to/certificate.p12 | pbcopy    </shiki-highlight>
  </div>
</div>
<h3 id="setting-up-the-signing-environment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Setting up the signing environment<a href="#setting-up-the-signing-environment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Setting up the signing environment"></a></h3>
<p>
In CI, you&#39;ll need to create a temporary keychain, set it as the default, and unlock it. Otherwise, the use of the system or login keychain, if it exists in remote environments, will most likely fail. Then, we base64-decode the certificate (and its key) and import it into the keychain:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
TMP_DIR=$(mktemp -d)
KEYCHAIN_PASSWORD=&quot;....&quot;
CERTIFICATE_PASSWORD=&quot;....&quot;
KEYCHAIN_PATH=$TMP_DIR/keychain.keychain
CERTIFICATE_PATH=$TMP_DIR/certificate.p12

echo &quot;$BASE_64_CERTIFICATE&quot; | base64 --decode &gt; $CERTIFICATE_PATH
security create-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security default-keychain -s $KEYCHAIN_PATH
security unlock-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P $CERTIFICATE_PASSWORD -A    </shiki-highlight>
  </div>
</div>
<h2 id="conclusion" tabindex="-1" class="marketing__blog_post__body__content__heading">
Conclusion<a href="#conclusion" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Conclusion"></a></h2>
<p>
By following the steps outlined in this guide, you can ensure that your CLI is properly signed and notarized for macOS. This not only helps in preventing security warnings but also builds trust with your users by ensuring that your software is from a verified source. Remember to regularly update your certificates and keep your signing and notarization processes up to date with Apple&#39;s guidelines to maintain a smooth user experience.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ 2024 Wrapped ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post, we reflect on what we did in 2024 and what's in our roadmap for 2025. ]]></summary>
      <link href="https://tuist.dev/blog/2024/12/21/2024-wrapped"/>
      <id>https://tuist.dev/blog/2024/12/21/2024-wrapped</id>
      <updated>Sat, 21 Dec 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When you decide to introduce Tuist into your toolchain, you are trusting us with your project, your team, and your time. Therefore, it&#39;s important for us to be transparent about what we do to earn that trust and what&#39;s in our plans to continue supporting you in the future. This blog post reflects what we did in 2024 and what&#39;s in our roadmap for 2025.</p>
<p>
Tuist started in 2017 as a project to conceptually compress the complexities and eliminate the annoyances of Xcode projects, and a lot has changed since then. Some long-standing issues like <a href="https://pepicrft.me/blog/2024/07/20/how-synchronized-groups-work-at-the-pbxproj-level">frequent merge conflicts</a> have been somewhat alleviated by Apple in Xcode 16, albeit still not completely resolved. They are also nudging projects away from bad practices like implicit module dependencies toward <a href="https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies">explicit ones</a>, and the community is pushing the Swift Package Manager and packages to be the building blocks to describe projects and avoid the Xcode project format altogether. As of today, we know <a href="https://medium.com/bumble-tech/scaling-ios-at-bumble-239e0fa009f2">it might not be a good idea</a> from a DX perspective, but with so much push from the community and resources from Apple, who knows what the future holds for the platform.</p>
<p>
With that context, we started to think about the role that Tuist should have in the ecosystem and how we could best support teams and developers in their journey of scaling development. What we concluded is that Tuist should embrace the existing toolchain, with its strengths and weaknesses, and connect to it as an extension instead of trying to abstract it away. We are not fans of abstractions, but in the case of Xcode project complexities, it was unavoidable. However, as Apple addresses the issues at more foundational layers, we can gear our efforts toward leveraging existing APIs to fill the gaps to work at scale. In that effort, we&#39;d dog-food and push the boundaries of what&#39;s possible with the existing APIs, and as more pieces become open-source by Apple, we&#39;d contribute back to the community.</p>
<p>
With the above context, let&#39;s dive right into our investments in 2024 and our roadmap for 2025.</p>
<h2 id="community---more-vibrant-than-ever" tabindex="-1" class="marketing__blog_post__body__content__heading">
Community - More vibrant than ever<a href="#community---more-vibrant-than-ever" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Community - More vibrant than ever"></a></h2>
<p>
When I think of Tuist&#39;s uniqueness, I think of its community. They are the ones that make Tuist what it is today. In 2024, we merged 723 pull requests in our repositories from over 321 contributors.</p>
<p>
In 2024, contributors also helped us translate 100% of our documentation to Korean, and work to translate it into Japanese, Portuguese, and Russian is ongoing. Meeting developers where they are also means meeting them in their language, and for that reason we invested and we&#39;ll continue to invest in making Tuist speak other languages.</p>
<p>
Having a healthy and vibrant community is a precious asset that we were struggling to nurture and support due to our limited resources, so earlier in the year we started to wonder whether Slack was the right platform for communication to happen. Similar questions repeated, the synchronous nature of the platform made it difficult to keep up with the conversation, and the closed nature of the platform made it difficult for us to put some tools in place to make the community more self-sufficient. For that reason, we decided to deploy our <a href="https://community.tuist.dev">own community forum</a> using <a href="https://www.discourse.org/index">Discourse</a>, the same solution that the <a href="https://forums.swift.org/">Swift community forum</a> uses. The forum encouraged deeper, longer, and more asynchronous conversations that are more peaceful to navigate. Moreover, search engines can index the content, so it&#39;s easier for developers to find answers to their questions. And Discourse has a rich set of plugins that we can use to make the community more self-sufficient. Why not GitHub Discussions, you might wonder... the reason is simple: for a reason we don&#39;t understand, GitHub Discussions is not well indexed by search engines, and there&#39;s no extensibility available, which is crucial for us to mold the forum to our needs.</p>
<h3 id="2025" tabindex="-1" class="marketing__blog_post__body__content__heading">
2025<a href="#2025" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2025"></a></h3>
<p>
In 2025, we&#39;ll roll out <a href="/blog/2024/10/29/tuist-ambassadors">the Tuist Ambassadors program</a> to recognize contributors who have gone above and beyond and support them in representing Tuist in the community. We&#39;ll also invest in improving the contribution experience by removing any friction in the process, and explore how to bring the community component to the features we are planning for the product. In the same vein as Dagger has built a <a href="https://daggerverse.dev/">Daggerverse</a> for their ecosystem of pipelines.</p>
<p>
In January, we&#39;ll start publishing issues in a new newsletter, <a href="https://community.tuist.dev/t/swift-stories-newsletter/275">&quot;Swift Stories&quot;</a>, which aims to create a cozy space for new voices to share their ideas. As part of our work at Tuist, we get to interact with many people who have great ideas and reflections that remain siloed because they don&#39;t feel they are worth sharing. We&#39;ll empower them through our newsletter and other initiatives to share their ideas with the community.</p>
<h2 id="product---from-project-generator-to-an-integrated-extension-of-apple's-toolchain" tabindex="-1" class="marketing__blog_post__body__content__heading">
Product - From project generator to an integrated extension of Apple&#39;s toolchain<a href="#product---from-project-generator-to-an-integrated-extension-of-apple's-toolchain" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Product - From project generator to an integrated extension of Apple's toolchain"></a></h2>
<p>
2024 was a year of <strong>transition</strong> for Tuist. We entered the year shifting from the idea that we are a project generator toward the idea that we are an integrated extension of Apple&#39;s toolchain. This is a shift that takes time because once people have formed an idea of what you are, it&#39;s difficult to change that perception. Still, we deem it necessary. Otherwise, new unrelated features start gravitating around a legacy solution, and people get even more confused. So you are a project generator, but you also do this and that.</p>
<p>
How to make that shift? Besides communicating it actively in every interaction with the community, we <strong>revamped our brand</strong>, which materialized in a new logo, marketing site, and documentation site. We consider the website a living organism, so we continue to iterate on it as we learn from our developer community. The amazing Guinda studio took on the task of <a href="/blog/2024/11/06/designing-tuist-website">designing our new website</a>, and as a result of that work, we also opened our <a href="https://www.figma.com/community/file/1436003642379974190/tuist-website-design-system">marketing design system</a> under the CC BY-SA 4.0 license. Did you notice our new title? &quot;Scale your Swift App development&quot;. It beautifully encapsulates our mission.</p>
<p>
We started the year officially introducing <a href="/blog/2024/04/25/tuist-cloud-free-for-open-source">a Tuist Server</a>, which we later consolidated into just Tuist (so no more cloud). We also invested in supporting Xcode 16 features from Tuist Projects and developed new features like <a href="https://docs.tuist.dev/en/guides/features/previews">Tuist Previews</a> (along with a <a href="/blog/2024/08/28/tuist-macos-app">macOS app</a>). Developers complained about compile-time of Swift Macros, so we <a href="/blog/2024/08/26/swift-macros">extended Tuist Cache</a> to support caching them too.</p>
<h3 id="2025" tabindex="-1" class="marketing__blog_post__body__content__heading">
2025<a href="#2025" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2025"></a></h3>
<p>
The first problem we&#39;ll solve in 2025 is slow Swift Package resolution that&#39;s inherent to SwiftPM&#39;s decentralized approach to package resolution using Git. We&#39;ll roll out a <a href="https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md">Swift Package Registry</a> that mirrors the packages from the <a href="https://swiftpackageindex.com/">Swift Package Index</a> and distributes them from a global storage network.</p>
<p>
Then our efforts will gravitate to two things:</p>
<ol>
  <li>
Bringing our insights and optimizations to vanilla Xcode projects (i.e. standard Xcode projects that are not defined with Tuist Projects&#39; DSL).  </li>
  <li>
Expanding metrics to projects, builds, and built products, and making them actionable  </li>
</ol>
<p>
At Tuist, we first focused on understanding Xcode projects and the build system, and optimizing them. We now think it&#39;s time to bring these optimizations to vanilla Xcode projects and Swift Packages, ensuring the adoption is as frictionless as possible. And with that foundation in place, we deem it crucial that teams have a deeper understanding of their development to make informed decisions. Our metrics will focus on projects, builds, tests, and built products, and we&#39;ll go the extra mile to make them actionable. <strong>Think of Tuist as the platform teams&#39; copilot or a virtual platform team.</strong> Not only will it tell you how things are going, but also the things that you might consider doing to improve your development environment and the apps that you build.</p>
<p>
In parallel, we&#39;ll start doing some explorations around <a href="https://en.wikipedia.org/wiki/Continuous_integration">CI</a>. It&#39;s a space where innovation has stagnated. Many Tuist users are vendor-locked into platforms through <a href="https://www.youtube.com/watch?v=UVED44sb7zg&t=12s">proprietary YAML schemas</a> and ecosystem of steps and are asked to pay abusive prices by some vendors. We want to help our developers move away from that, and we are going to take the opportunity to rethink the space. Our investment will gravitate around three needs that remain unaddressed today:</p>
<ol>
  <li>
Debugging a pipeline locally is not possible  </li>
  <li>
There&#39;s too much indirection (CI &gt; Proprietary YAML &gt; Scripts (e.g. Fastlane) &gt; Apple toolchain &gt; Xcode Project)  </li>
  <li>
Developers love using Swift for everything  </li>
</ol>
<p>
So expect some new open-source projects in this space in 2025. More on our open-source strategy further down.</p>
<h2 id="engineering---embracing-simplicity" tabindex="-1" class="marketing__blog_post__body__content__heading">
Engineering - Embracing simplicity<a href="#engineering---embracing-simplicity" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Engineering - Embracing simplicity"></a></h2>
<p>
We are a small team with limited resources, and this is something that we&#39;ve embraced as positive. Since we can&#39;t afford throwing money at problems, early in 2024 we wondered what technology strikes the best balance between powerfulness and costs (i.e., development and scaling). It was then when we crossed paths with <a href="https://elixir-lang.org/">Elixir</a>, which builds on a very matured and battle-tested runtime, <a href="https://www.erlang.org/">Erlang</a>, to build fault-tolerant and scalable systems. We didn&#39;t think twice. We rewrote the Tuist server from Ruby into Elixir, and we never looked back. Unlike many other solutions, which present themselves as simple while abstracting a world of complexity that sooner or later becomes costly, Elixir and Erlang are simple by principles and concepts.</p>
<p>
The functional nature of the language and the actor model makes it possible to parallelize test runs without introducing flakiness. We can scale servers vertically by adding more CPU and memory, and all we really need is a powerful server instance. Its hot-reloading capabilities in development have been crucial for speed of iteration, and the same goes for its REPL when it comes to debugging issues. We are also embracing web standards as much as possible to minimize dependency on layers of proprietary abstractions that can disrupt and distract us from our mission. The interaction between the CLI and the server is through a well-documented <a href="https://cloud.tuist.io/api/docs">REST API</a> (we plan to open it to third-party developers down the road). Our UIs are <a href="https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html">Phoenix LiveView</a>, and our upcoming design system will make use of <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">Web Components</a>. One of the beauties of the web platform is that it&#39;s always backward compatible, so if we embrace it, the Tuist that we build on the server will work today, next week, and in years to come, and the team will pour its limited resources into bringing more value and not keeping up with trends.</p>
<p>
In 2024, we also commoditized some Tuist components, like <a href="https://github.com/tuist/xcodegraph">XcodeGraph</a>, and thanks to <a href="https://github.com/ajkolean">Andy</a>&#39;s <a href="https://github.com/tuist/XcodeGraph/pull/87">amazing work</a>, the investment is already paying off since you&#39;ll soon be able to use some Tuist features like selective testing with vanilla Xcode projects. Isn&#39;t it amazing? We also created <a href="https://github.com/tuist/path">Path</a>, forking some utilities from <a href="https://github.com/apple/swift-tools-support-core">swift-tools-support-core</a>, standardized file-system operations across Tuist packages with another open source project, <a href="https://github.com/tuist/FileSystem/">FileSystem</a>. We also open-sourced <a href="https://github.com/tuist/command/">Command</a> to run system processes in Linux and macOS environments. </p>
<p>
One common denominator across all the technical efforts in the CLI is that we are trying to make the foundational pieces work with macOS, Linux, and soon Windows, in case we need Tuist to support other ecosystems in the future where developers might need to run the CLI from Linux or Windows environments.</p>
<p>
Thanks to Swift Macros and <a href="https://github.com/Kolos65">Kolos Foltányi</a>&#39;s amazing work with <a href="https://github.com/Kolos65/Mockable">Mockable</a>, which we started adopting in our codebase, we are now saving a lot of time not writing the mocks that we used to write. We also started adopting <a href="https://developer.apple.com/xcode/swift-testing/">Swift Testing</a>, and we are quite pleased with the experience so far.</p>
<p>
In 2024, we also made a fair investment in bringing performance improvements to the project generation by parallelizing operations that previously ran sequentially.</p>
<h3 id="2025" tabindex="-1" class="marketing__blog_post__body__content__heading">
2025<a href="#2025" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2025"></a></h3>
<p>
In 2025, we&#39;ll iterate on our architecture to dependency-inject core utilities to be able to isolate each test case and run them in parallel without the risk of introducing flakiness. As part of the development of some features, we&#39;ll open-source and maintain some commodities for the community to build upon.</p>
<h2 id="design---laying-a-missing-foundation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Design - Laying a missing foundation<a href="#design---laying-a-missing-foundation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Design - Laying a missing foundation"></a></h2>
<p>
Since the first line of code, the focus of Tuist has always been on code craft. For the surface where design was needed, like the CLI output and input (e.g., names, flags), and the website, we always tried to keep it simple and functional. It served us well for a long time, but as Tuist takes shape in new platforms, like our macOS app and the dashboard, it&#39;s time to stop treating design as an afterthought and start investing in it.</p>
<p>
When it comes to code, sooner or later in the lifecycle of a project, you start extracting the common elements into reusable code utilities and frameworks for consistency and reusability. The same notion applies to design, and the extraction of common patterns for reusability and consistency usually manifests as a design system. Guess what, that&#39;s what we started doing in 2024.</p>
<p>
<a href="https://bsky.app/profile/asmitbm.bsky.social">Asmit</a> took on the task of coming up with a design system for Tuist. He <a href="https://community.tuist.dev/t/redesign-initiative-at-tuist/138/5">shared the progress with the community</a> and is almost done with the first iteration. And as huge fans of open source as we are, the design system will be open too for anyone to use. We&#39;ll soon start converting it to web components that are easily reusable across websites. At first, we&#39;ll use them in the Tuist dashboard, and then in some CLI features like <a href="https://community.tuist.dev/t/enhancing-tuists-graph-command-with-interactive-graph/225">interactive graphs</a>, which are CLI features that don&#39;t need a server.</p>
<p>
Inspired by <a href="https://www.ruby-lang.org/en/">Ruby</a> and <a href="https://rubyonrails.org/">Ruby on Rails</a>, we&#39;ve always optimized for joy. At the end of the day, who doesn&#39;t like enjoyable experiences when using technology? That&#39;s one of the reasons why Apple is so successful when building products. They put meticulous attention to detail in the design of their products. When we look at the developer space, we see quite the opposite: data and randomly designed components stitched together and information competing for attention. Or even worse, sales or marketing leaking into the product anywhere you go. We have an excellent opportunity in front of us to do things differently, and let me tell you something: we won&#39;t miss it.</p>
<p>
  <img src="/marketing/images/blog/2024/12/21/2024-wrapped/buttons.png" alt="An image that shows the looking of the icons in our design system">
</p>
<p>
Design systems are not just about consistency; they&#39;re about agility. Since we&#39;ll have a common language between developers and designers, and a set of reusable components ready to use, a lot of the work will revolve around assembling them and presenting content in them. I still remember my time at Shopify when we used <a href="https://polaris.shopify.com/">Polaris</a> to build some internal services, and the speed of delivery was just unbeatable.</p>
<h3 id="2025" tabindex="-1" class="marketing__blog_post__body__content__heading">
2025<a href="#2025" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2025"></a></h3>
<p>
The first feature that makes use of the design system will be our dashboard. We&#39;ll redesign it from the ground up, bringing feature parity with the CLI, and bringing workflows that have traditionally been CLI-first, like adding Tuist to a project, which you&#39;ll soon be able to do right from the web. Remember the mobile-first trend? We&#39;ve been CLI-first too, like <a href="https://fly.io/">Fly</a> is, and we&#39;ll continue to be so, but we&#39;ll make sure operations are also achievable through a beautifully designed dashboard.</p>
<p>
We&#39;ll also pour resources into improving the design of the CLI output. With no control, it&#39;s easy to end up with outputs that are hard to parse and understand. So like we are doing for the web, we are open-sourcing a design system for Swift CLIs, <a href="https://github.com/tuist/noora">Noora</a>, which we&#39;ll adopt throughout the CLI. We&#39;ll separate and differentiate between logging, which we are turning into a debugging tool, and treat user output more like UI in a standard AppleOS application. Terminals are limiting environments, but they spark a lot of creativity.</p>
<h2 id="business---building-a-different-business" tabindex="-1" class="marketing__blog_post__body__content__heading">
Business - Building a different business<a href="#business---building-a-different-business" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Business - Building a different business"></a></h2>
<p>
When you enter a business relationship with another company through a service they provide, you are introducing some risk to your development or operations. The company you transitively depend on through a service might go bankrupt, take a direction that doesn&#39;t align with your needs or values, or leverage their competitive advantage in a market to roll out abusive prices that you can do little about. We are seeing a lot of this last one in the CI space. Deciding on a service is a decision that can&#39;t be taken lightly, despite many companies doing so.</p>
<p>
As surprising as it sounds, when the dependency is on one or two developers who are building open source software that you depend on, the risks are more often ignored. When you all decided to introduce such a foundational tool as Tuist into your workflows, you all trusted us to minimize that risk for you. And minimizing that risk is in fact what motivated us to build Tuist as a company, a different type of company.</p>
<p>
The support and requests work demanded people to be full-time on Tuist, and that required us to bring some business structure to the project. We drew a line between the CLI and the server. CLI-only features would be free, and those that required a server would be paid. We&#39;d keep the server closed-source until we could financially secure the resources needed to support Tuist. Since we knew a closed-source server could be concerning for some of you, we did something unique that not many companies provide: a <a href="/longevity">longevity plan</a>. What does that mean for you? Simply put, if we screw things up, the code of the server will be open-sourced and given to the community. We believe that&#39;s the right thing to do.</p>
<p>
But just that is not enough. What if for any reason, you disagree with us and want to take your project elsewhere? In a traditional model, it would be so painful that you&#39;d rather stick with the service and hope for the best. Just not so long ago, I was told that some CI providers are offering to &quot;migrate your CI pipelines for free.&quot; How bizarre is that? If that&#39;s a business practice that companies are adopting, we are doing something wrong as an industry. We need to do better. For that reason, we bet on standards and open source as much as we can because we respect people&#39;s freedom to choose, and Tuist is no one to get in their way.</p>
<p>
So our model is simple. We monetize the server features to develop more open source software. Server features are usually features that large enterprises need and are willing to pay for, so we funnel capital to support not only open source but also indie developers and small startups that are getting started. I think it&#39;s a beautiful model.</p>
<p>
We also embraced a different pricing model compared to the norm in the industry. Since these tools are geared towards large enterprises, they place a &quot;contact sales&quot; option on their website and put you in the position to have great negotiation skills to get the best price out of it. Additionally, they give you a very limited demo so that you get a taste of it, and the demo is slapped with &quot;contact sales&quot; buttons everywhere. Once again, we think we are doing something wrong as an industry. So we decided to take a <a href="/blog/2024/11/05/our-pricing-philosophy">different approach</a> based on three principles:</p>
<ol>
  <li>
We charge per usage  </li>
  <li>
You don&#39;t pay if you don&#39;t use it enough  </li>
  <li>
We aim to be the cheapest at every scale  </li>
</ol>
<p>
The model is working exceptionally well. Companies already using Tuist are now becoming customers of our paid features, helping us continue to build even more open-source software. Some, like Trendyol, have even gone so far as to provide us with a <a href="/blog/2024/12/16/trendyol">case study</a> unsolicited, which is truly humbling. We&#39;ve seen steady conversion, and we&#39;re already collaborating with several other companies to bring them on board as customers.</p>
<p>
Beyond that, we’ve learned a great deal about German bureaucracy and the nuances of running a business—things like taxes, accounting, contracts, and most recently, hiring. <a href="https://fosstodon.org/@cschmatzler">Christoph</a> and <a href="https://mastodon.social/@asmitbm">Asmit</a> are officially joining us full-time in January 2025, and I can&#39;t wait for them to get started. We’re a small team, but one that is poised to make a significant impact in the industry.</p>
<h3 id="2025" tabindex="-1" class="marketing__blog_post__body__content__heading">
2025<a href="#2025" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2025"></a></h3>
<p>
In 2025, we’ll continue to work with organizations adopting our paid features, helping them integrate these solutions into their workflows. Alongside this, we’ll invest in enhancing the Tuist CLI and developing other essential tools for the ecosystem. We’ll also be releasing new features tailored to small startups and indie developers, offering them self-upgrade options with minimal costs based on their usage.</p>
<p>
In Q1 2025, we expect to obtain the SOC 2 certification, which should accelerate our ability to become a vendor for companies requiring this certification.</p>
<h2 id="marketing---our-community-is-our-best-marketing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Marketing - Our community is our best marketing<a href="#marketing---our-community-is-our-best-marketing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Marketing - Our community is our best marketing"></a></h2>
<p>
As you may have noticed, we’ve spent very little on marketing. When you spend money on marketing, it becomes forced. You can get people to talk about you, write about you, or put you in front of people—but that only works as long as you continue to spend.</p>
<p>
Instead, we focus on being human with our community. What does that mean? We nurture our community and empower its members. They connect with the project in such a unique way that they become our most powerful marketing tool. That’s how we’ve gained such popularity in countries like South Korea, without spending a dime on marketing there. It’s truly mind-blowing.</p>
<p>
This might go against conventional marketing advice, but believe me, the best marketing comes from the people you support and empower. For this reason, much of what we do focuses on the people rather than ourselves. When <a href="https://community.tuist.dev/t/swift-stories-newsletter/275">we decided to launch a newsletter</a>, it was clear from the start that the focus would be the community, not us. That’s why it’s called &quot;Swift Stories&quot; and not &quot;The Tuist Newsletter.&quot;</p>
<p>
We’ve also sponsored conferences to support community-driven initiatives, but we’ve never seen that as a marketing tactic. We draw inspiration from what others are doing and help them along their journey. We don’t believe in paying people to talk about us. If you like Tuist and want to write about it, that’s amazing! We’re forever grateful, and we’ll send you tokens of appreciation, but we won’t pay you for it.</p>
<h3 id="2025" tabindex="-1" class="marketing__blog_post__body__content__heading">
2025<a href="#2025" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2025"></a></h3>
<p>
In 2025, our marketing efforts will continue to center around the same philosophy—investing in our community and community-driven projects, like our newsletter. We’ve also considered launching a podcast, but due to time constraints, we’ll have to delay it for now. It’s something we’ve always dreamed of doing, so we’ll make it happen eventually.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
It’s incredible to look back and see how much we’ve accomplished in 2024 with just two people working full-time, alongside our open-source community. The Tuist project is more vibrant than ever, and we’re excited for what 2025 holds.</p>
<h3 id="contributors" tabindex="-1" class="marketing__blog_post__body__content__heading">
Contributors<a href="#contributors" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Contributors"></a></h3>
<p>
Whether you’re using Tuist, contributing to it, or helping maintain it, I’d like to personally thank you for being part of this journey. We’re building something special here, and we’re doing it together.</p>
<p>
And huge thanks to all those who contributed to Tuist in 2024:</p>
<p>
<a href="https://github.com/danieleformichelli">danieleformichelli</a>, <a href="https://github.com/ollieatkinson">ollieatkinson</a>, <a href="https://github.com/kwridan">kwridan</a>, <a href="https://github.com/waltflanagan">waltflanagan</a>, <a href="https://github.com/adellibovi">adellibovi</a>, <a href="https://github.com/laxmorek">laxmorek</a>, <a href="https://github.com/olejnjak">olejnjak</a>, <a href="https://github.com/actions-user">actions-user</a>, <a href="https://github.com/lakpa">lakpa</a>, <a href="https://github.com/andreacipriani">andreacipriani</a>, <a href="https://github.com/mollyIV">mollyIV</a>, <a href="https://github.com/RomainBoulay">RomainBoulay</a>, <a href="https://github.com/natanrolnik">natanrolnik</a>, <a href="https://github.com/ezraberch">ezraberch</a>, <a href="https://github.com/vytis">vytis</a>, <a href="https://github.com/alexanderwe">alexanderwe</a>, <a href="https://github.com/luispadron">luispadron</a>, <a href="https://github.com/adamkhazi">adamkhazi</a>, <a href="https://github.com/hisaac">hisaac</a>, <a href="https://github.com/facumenzella">facumenzella</a>, <a href="https://github.com/marciniwanicki">marciniwanicki</a>, <a href="https://github.com/regularberry">regularberry</a>, <a href="https://github.com/danyf90">danyf90</a>, <a href="https://github.com/hebertialmeida">hebertialmeida</a>, <a href="https://github.com/rowwingman">rowwingman</a>, <a href="https://github.com/mikchmie">mikchmie</a>, <a href="https://github.com/thedavidharris">thedavidharris</a>, <a href="https://github.com/LorDisturbia">LorDisturbia</a>, <a href="https://github.com/iteracticman">iteracticman</a>, <a href="https://github.com/leszko11">leszko11</a>, <a href="https://github.com/frijole">frijole</a>, <a href="https://github.com/danibachar">danibachar</a>, <a href="https://github.com/dangthaison91">dangthaison91</a>, <a href="https://github.com/maciejpiotrowski89">maciejpiotrowski89</a>, <a href="https://github.com/rofle100lvl">rofle100lvl</a>, <a href="https://github.com/yurapriv">yurapriv</a>, <a href="https://github.com/ferologics">ferologics</a>, <a href="https://github.com/freak4pc">freak4pc</a>, <a href="https://github.com/woin2ee">woin2ee</a>, <a href="https://github.com/anlaital-oura">anlaital-oura</a>, <a href="https://github.com/cpisciotta">cpisciotta</a>, <a href="https://github.com/dcvz">dcvz</a>, <a href="https://github.com/kapitoshka438">kapitoshka438</a>, <a href="https://github.com/KaiOelfke">KaiOelfke</a>, <a href="https://github.com/jsorge">jsorge</a>, <a href="https://github.com/serejahh">serejahh</a>, <a href="https://github.com/Lilfaen">Lilfaen</a>, <a href="https://github.com/TheInkedEngineer">TheInkedEngineer</a>, <a href="https://github.com/apps4everyone">apps4everyone</a>, <a href="https://github.com/fila95">fila95</a>, <a href="https://github.com/hiltonc">hiltonc</a>, <a href="https://github.com/TamarMilchtaich">TamarMilchtaich</a>, <a href="https://github.com/wattson12">wattson12</a>, <a href="https://github.com/mstfy">mstfy</a>, <a href="https://github.com/rgnns">rgnns</a>, <a href="https://github.com/ffittschen">ffittschen</a>, <a href="https://github.com/erkekin">erkekin</a>, <a href="https://github.com/DimaMishchenko">DimaMishchenko</a>, <a href="https://github.com/paulsamuels">paulsamuels</a>, <a href="https://github.com/devyhan">devyhan</a>, <a href="https://github.com/foyoodo">foyoodo</a>, <a href="https://github.com/svenmuennich">svenmuennich</a>, <a href="https://github.com/pewegela">pewegela</a>, <a href="https://github.com/raven">raven</a>, <a href="https://github.com/MontakOleg">MontakOleg</a>, <a href="https://github.com/Rag0n">Rag0n</a>, <a href="https://github.com/ladislas">ladislas</a>, <a href="https://github.com/jeroenleenarts">jeroenleenarts</a>, <a href="https://github.com/zhuhaow">zhuhaow</a>, <a href="https://github.com/jakeatoms">jakeatoms</a>, <a href="https://github.com/baekteun">baekteun</a>, <a href="https://github.com/minhaaan">minhaaan</a>, <a href="https://github.com/jrescabias">jrescabias</a>, <a href="https://github.com/chojnac">chojnac</a>, <a href="https://github.com/shahzadmajeed">shahzadmajeed</a>, <a href="https://github.com/pavel-trafimuk">pavel-trafimuk</a>, <a href="https://github.com/PaulTaykalo">PaulTaykalo</a>, <a href="https://github.com/AlbGarciam">AlbGarciam</a>, <a href="https://github.com/xoxo-anastasi-xoxo">xoxo-anastasi-xoxo</a>, <a href="https://github.com/davebcn87">davebcn87</a>, <a href="https://github.com/morozkin">morozkin</a>, <a href="https://github.com/dxmvsh">dxmvsh</a>, <a href="https://github.com/esttorhe">esttorhe</a>, <a href="https://github.com/moritzsternemann">moritzsternemann</a>, <a href="https://github.com/nandodelauni">nandodelauni</a>, <a href="https://github.com/miscampbell">miscampbell</a>, <a href="https://github.com/bolismauro">bolismauro</a>, <a href="https://github.com/Jake-Prickett">Jake-Prickett</a>, <a href="https://github.com/FranzBusch">FranzBusch</a>, <a href="https://github.com/DevVenusK">DevVenusK</a>, <a href="https://github.com/santos88">santos88</a>, <a href="https://github.com/spqw">spqw</a>, <a href="https://github.com/vijaytholpadi">vijaytholpadi</a>, <a href="https://github.com/ahmdyasser">ahmdyasser</a>, <a href="https://github.com/costapombo">costapombo</a>, <a href="https://github.com/dankinsoid">dankinsoid</a>, <a href="https://github.com/kyungpyoda">kyungpyoda</a>, <a href="https://github.com/mustiikhalil">mustiikhalil</a>, <a href="https://github.com/oozoofrog">oozoofrog</a>, <a href="https://github.com/dp221125">dp221125</a>, <a href="https://github.com/thelvis4">thelvis4</a>, <a href="https://github.com/tovkal">tovkal</a>, <a href="https://github.com/zdnk">zdnk</a>, <a href="https://github.com/darrarski">darrarski</a>, <a href="https://github.com/softmaxsg">softmaxsg</a>, <a href="https://github.com/woohyunjin06">woohyunjin06</a>, <a href="https://github.com/setoelkahfi">setoelkahfi</a>, <a href="https://github.com/rsarv3006">rsarv3006</a>, <a href="https://github.com/fuzza">fuzza</a>, <a href="https://github.com/orbitekk">orbitekk</a>, <a href="https://github.com/lo1tuma">lo1tuma</a>, <a href="https://github.com/michaelmcguire">michaelmcguire</a>, <a href="https://github.com/Binlogo">Binlogo</a>, <a href="https://github.com/dcordero">dcordero</a>, <a href="https://github.com/cristi-lupu">cristi-lupu</a>, <a href="https://github.com/DavidBrunow">DavidBrunow</a>, <a href="https://github.com/david-all-win-software">david-all-win-software</a>, <a href="https://github.com/ajkolean">ajkolean</a>, <a href="https://github.com/Arideno">Arideno</a>, <a href="https://github.com/dogo">dogo</a>, <a href="https://github.com/roanutil">roanutil</a>, <a href="https://github.com/DevilDimon">DevilDimon</a>, <a href="https://github.com/Andrea-Scuderi">Andrea-Scuderi</a>, <a href="https://github.com/Ernest0-Production">Ernest0-Production</a>, <a href="https://github.com/mfcollins3">mfcollins3</a>, <a href="https://github.com/havebeenfitz">havebeenfitz</a>, <a href="https://github.com/mihaicris-adoreme">mihaicris-adoreme</a>, <a href="https://github.com/L-j-h-c">L-j-h-c</a>, <a href="https://github.com/myihsan">myihsan</a>, <a href="https://github.com/InderKumarRathore">InderKumarRathore</a>, <a href="https://github.com/iainsmith">iainsmith</a>, <a href="https://github.com/nicholaskim94">nicholaskim94</a>, <a href="https://github.com/gustn3965">gustn3965</a>, <a href="https://github.com/GermanVelibekovHouzz">GermanVelibekovHouzz</a>, <a href="https://github.com/PierreCapo">PierreCapo</a>, <a href="https://github.com/codeOfRobin">codeOfRobin</a>, <a href="https://github.com/griches">griches</a>, <a href="https://github.com/sphanley">sphanley</a>, <a href="https://github.com/sampettersson">sampettersson</a>, <a href="https://github.com/saim80">saim80</a>, <a href="https://github.com/SergeyPetrachkov">SergeyPetrachkov</a>, <a href="https://github.com/fdzsergio">fdzsergio</a>, <a href="https://github.com/schinj">schinj</a>, <a href="https://github.com/MagnificentMiles">MagnificentMiles</a>, <a href="https://github.com/tdkn">tdkn</a>, <a href="https://github.com/simpers">simpers</a>, <a href="https://github.com/JCSooHwanCho">JCSooHwanCho</a>, <a href="https://github.com/st-small">st-small</a>, <a href="https://github.com/steprescott">steprescott</a>, <a href="https://github.com/rist">rist</a>, <a href="https://github.com/stefanomondino">stefanomondino</a>, <a href="https://github.com/kalkwarf">kalkwarf</a>, <a href="https://github.com/stevelandeyasana">stevelandeyasana</a>, <a href="https://github.com/stephanecopin">stephanecopin</a>, <a href="https://github.com/sujata23">sujata23</a>, <a href="https://github.com/doulos76">doulos76</a>, <a href="https://github.com/devMinseok">devMinseok</a>, <a href="https://github.com/mohitsaxenaknoldus">mohitsaxenaknoldus</a>, <a href="https://github.com/tosbaha">tosbaha</a>, <a href="https://github.com/NataliaKurek">NataliaKurek</a>, <a href="https://github.com/NickZemlin">NickZemlin</a>, <a href="https://github.com/nivanchikov">nivanchikov</a>, <a href="https://github.com/oronbz">oronbz</a>, <a href="https://github.com/Austinate">Austinate</a>, <a href="https://github.com/wogus3602">wogus3602</a>, <a href="https://github.com/BalestraPatrick">BalestraPatrick</a>, <a href="https://github.com/pavm035">pavm035</a>, <a href="https://github.com/petrukha-ivan">petrukha-ivan</a>, <a href="https://github.com/platonsi">platonsi</a>, <a href="https://github.com/PushedCrayon">PushedCrayon</a>, <a href="https://github.com/Arafo">Arafo</a>, <a href="https://github.com/OhKanghoon">OhKanghoon</a>, <a href="https://github.com/enlivn">enlivn</a>, <a href="https://github.com/rhysm94">rhysm94</a>, <a href="https://github.com/rmnblm">rmnblm</a>, <a href="https://github.com/RomanPodymov">RomanPodymov</a>, <a href="https://github.com/aniltaskiran">aniltaskiran</a>, <a href="https://github.com/brianvar">brianvar</a>, <a href="https://github.com/cheskapac">cheskapac</a>, <a href="https://github.com/dcramps">dcramps</a>, <a href="https://github.com/honghoker">honghoker</a>, <a href="https://github.com/euriasb">euriasb</a>, <a href="https://github.com/ibrahimoktay">ibrahimoktay</a>, <a href="https://github.com/jimmy-li-houzz">jimmy-li-houzz</a>, <a href="https://github.com/kimxwan0319">kimxwan0319</a>, <a href="https://github.com/kyounh12">kyounh12</a>, <a href="https://github.com/MariusDeReus">MariusDeReus</a>, <a href="https://github.com/pierrerodgers">pierrerodgers</a>, <a href="https://github.com/ronanociosoig-200">ronanociosoig-200</a>, <a href="https://github.com/sabade-omkar">sabade-omkar</a>, <a href="https://github.com/sh-a-n">sh-a-n</a>, <a href="https://github.com/sonuvryahoo">sonuvryahoo</a>, <a href="https://github.com/vendulasvastal">vendulasvastal</a>, <a href="https://github.com/tatagrigory">tatagrigory</a>, <a href="https://github.com/tzxdtc">tzxdtc</a>, <a href="https://github.com/jihoonahn">jihoonahn</a>, <a href="https://github.com/c0diq">c0diq</a>, <a href="https://github.com/TahaTesser">TahaTesser</a>, <a href="https://github.com/ActuallyTaylor">ActuallyTaylor</a>, <a href="https://github.com/tejassharma96">tejassharma96</a>, <a href="https://github.com/ThiemeFM">ThiemeFM</a>, <a href="https://github.com/takinwande">takinwande</a>, <a href="https://github.com/hoangatuan">hoangatuan</a>, <a href="https://github.com/tiarnann">tiarnann</a>, <a href="https://github.com/vkrol">vkrol</a>, <a href="https://github.com/victor-sarda">victor-sarda</a>, <a href="https://github.com/VilleWitt">VilleWitt</a>, <a href="https://github.com/vcoutasso">vcoutasso</a>, <a href="https://github.com/in4lio">in4lio</a>, <a href="https://github.com/vldalx">vldalx</a>, <a href="https://github.com/khramtsoff">khramtsoff</a>, <a href="https://github.com/SpectralDragon">SpectralDragon</a>, <a href="https://github.com/wangjiejacques">wangjiejacques</a>, <a href="https://github.com/wojciech-kulik">wojciech-kulik</a>, <a href="https://github.com/Buju77">Buju77</a>, <a href="https://github.com/neakor">neakor</a>, <a href="https://github.com/yungu0010">yungu0010</a>, <a href="https://github.com/zzzkk">zzzkk</a>, <a href="https://github.com/aegzorz">aegzorz</a>, <a href="https://github.com/acosmicflamingo">acosmicflamingo</a>, <a href="https://github.com/cruisediary">cruisediary</a>, <a href="https://github.com/Killectro">Killectro</a>, <a href="https://github.com/danrevah">danrevah</a>, <a href="https://github.com/dansinclair25">dansinclair25</a>, <a href="https://github.com/dbarden">dbarden</a>, <a href="https://github.com/danielmoro">danielmoro</a>, <a href="https://github.com/DarkoDamjanovic">DarkoDamjanovic</a>, <a href="https://github.com/buresdv">buresdv</a>, <a href="https://github.com/Primecutz">Primecutz</a>, <a href="https://github.com/cieslakdawid">cieslakdawid</a>, <a href="https://github.com/decanus">decanus</a>, <a href="https://github.com/denil-ct">denil-ct</a>, <a href="https://github.com/francuim-d">francuim-d</a>, <a href="https://github.com/dever25">dever25</a>, <a href="https://github.com/navartis">navartis</a>, <a href="https://github.com/Dmitry-Pliushchai">Dmitry-Pliushchai</a>, <a href="https://github.com/DmitrySerovWise">DmitrySerovWise</a>, <a href="https://github.com/eddieh">eddieh</a>, <a href="https://github.com/ElonPark">ElonPark</a>, <a href="https://github.com/bogren">bogren</a>, <a href="https://github.com/eito">eito</a>, <a href="https://github.com/Juanpe">Juanpe</a>, <a href="https://github.com/abbasmousavi">abbasmousavi</a>, <a href="https://github.com/alpanyukov">alpanyukov</a>, <a href="https://github.com/alexfilimon">alexfilimon</a>, <a href="https://github.com/Smponias">Smponias</a>, <a href="https://github.com/alvar-bolt">alvar-bolt</a>, <a href="https://github.com/alvarhansen">alvarhansen</a>, <a href="https://github.com/andruvs">andruvs</a>, <a href="https://github.com/rock88">rock88</a>, <a href="https://github.com/aim2120">aim2120</a>, <a href="https://github.com/Garfeild">Garfeild</a>, <a href="https://github.com/a-sarris">a-sarris</a>, <a href="https://github.com/Gladkov-Art">Gladkov-Art</a>, <a href="https://github.com/astromonkee">astromonkee</a>, <a href="https://github.com/ajevans99">ajevans99</a>, <a href="https://github.com/barakwei">barakwei</a>, <a href="https://github.com/BarredEwe">BarredEwe</a>, <a href="https://github.com/batuhansk">batuhansk</a>, <a href="https://github.com/BenjaminPrieur">BenjaminPrieur</a>, <a href="https://github.com/bhuemer">bhuemer</a>, <a href="https://github.com/brunoorocha">brunoorocha</a>, <a href="https://github.com/csjones">csjones</a>, <a href="https://github.com/chris-livefront">chris-livefront</a>, <a href="https://github.com/cconstable">cconstable</a>, <a href="https://github.com/JulianAlonso">JulianAlonso</a>, <a href="https://github.com/kabirkhaan">kabirkhaan</a>, <a href="https://github.com/nagra">nagra</a>, <a href="https://github.com/avbangar">avbangar</a>, <a href="https://github.com/kevin58332">kevin58332</a>, <a href="https://github.com/kevinrandrup">kevinrandrup</a>, <a href="https://github.com/kientux">kientux</a>, <a href="https://github.com/UniekLee">UniekLee</a>, <a href="https://github.com/lucabartoletti">lucabartoletti</a>, <a href="https://github.com/lucasmpaim">lucasmpaim</a>, <a href="https://github.com/luciav-github">luciav-github</a>, <a href="https://github.com/lm2s">lm2s</a>, <a href="https://github.com/mpodeszwa">mpodeszwa</a>, <a href="https://github.com/MartinStrambach">MartinStrambach</a>, <a href="https://github.com/MarvinNazari">MarvinNazari</a>, <a href="https://github.com/Mstrodl">Mstrodl</a>, <a href="https://github.com/MatyasKriz">MatyasKriz</a>, <a href="https://github.com/Speakus">Speakus</a>, <a href="https://github.com/michalsrutek">michalsrutek</a>, <a href="https://github.com/mikeger">mikeger</a>, <a href="https://github.com/mgray88">mgray88</a>, <a href="https://github.com/akaDuality">akaDuality</a>, <a href="https://github.com/Ethan-IS">Ethan-IS</a>, <a href="https://github.com/Lommelun">Lommelun</a>, <a href="https://github.com/filipracki">filipracki</a>, <a href="https://github.com/MrCloud">MrCloud</a>, <a href="https://github.com/gcacoutinho">gcacoutinho</a>, <a href="https://github.com/gaetanomatonti">gaetanomatonti</a>, <a href="https://github.com/Arclite">Arclite</a>, <a href="https://github.com/mangofever">mangofever</a>, <a href="https://github.com/grdsdev">grdsdev</a>, <a href="https://github.com/Tulleb">Tulleb</a>, <a href="https://github.com/haeseoklee">haeseoklee</a>, <a href="https://github.com/haifengkao">haifengkao</a>, <a href="https://github.com/swiftty">swiftty</a>, <a href="https://github.com/HossamYoussof">HossamYoussof</a>, <a href="https://github.com/isavynskyi">isavynskyi</a>, <a href="https://github.com/eltociear">eltociear</a>, <a href="https://github.com/ilia3546">ilia3546</a>, <a href="https://github.com/TheImShrey">TheImShrey</a>, <a href="https://github.com/unxavi">unxavi</a>, <a href="https://github.com/jesus-mg-ios">jesus-mg-ios</a>, <a href="https://github.com/mo5tone">mo5tone</a>, <a href="https://github.com/jinuman">jinuman</a>, <a href="https://github.com/johnyorke">johnyorke</a></p>
<p>
And the following people have contributed translations to Tuist in 2024:</p>
<p>
<a href="https://tedokon.com/">Shun Tedokon</a>, <a href="https://github.com/honghoker">eunpyo hong</a>, <a href="https://github.com/ungchun">sunghun</a>, <a href="https://github.com/bbiguduk">Boram Jeong</a>, <a href="https://github.com/trickart">Trickart</a>, <a href="https://github.com/Uhucream">Takashi</a>, <a href="https://kkodiac.github.io/">Sean Hong</a>, <a href="https://www.linkedin.com/in/%ED%9A%A8%EC%84%B1-%EA%B9%80-9721a0167">김효성 (devvenusk)</a>, <a href="https://github.com/2sem">leesam</a>, <a href="https://github.com/Roy-wonji">Roy</a></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Trendyol reduced build times by 65% ]]></title>
      
      
      <author>
        <name><![CDATA[ Trendyol ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Trendyol reduced build times by 65% with Tuist, cutting CI builds to 10 minutes and local UI test setups to 30 seconds. Their self-hosted Tuist instance ensures secure, fast performance, streamlining workflows for 170+ developers. ]]></summary>
      <link href="https://tuist.dev/customers/trendyol"/>
      <id>https://tuist.dev/customers/trendyol</id>
      <updated>Mon, 16 Dec 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <h2 id="the-challenge" tabindex="-1" class="marketing__blog_post__body__content__heading">
The challenge<a href="#the-challenge" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The challenge"></a></h2>
<p>
At <a href="https://www.trendyol.com">Trendyol</a>, our journey with Tuist began as we needed to organize our large and complex project structures across multiple teams and domains. Even after introducing selective unit testing to accelerate our feedback loop by up to 80%, both local and CI builds continued to stretch beyond 30 minutes, affecting the pace at which developers could iterate.</p>
<p>
As Turkey&#39;s leading e-commerce platform and a super-app serving more than 10 domain teams and 170+ developers across iOS and Android, speed at scale is supreme. To further optimize our workflows, we took the next logical step: leveraging Tuist Cache to improve build times and deliver a better overall developer experience.</p>
<h2 id="choosing-tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Choosing Tuist<a href="#choosing-tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Choosing Tuist"></a></h2>
<p>
Originally, our motivation with Tuist was to enable caching for local development. Although CI speed matters, it&#39;s the local feedback loops that directly influence a developer&#39;s ability to experiment quickly. Once we began using the <a href="https://docs.tuist.dev/en/server/introduction/why-a-server">Tuist Server</a>, we saw immediate benefits. With effective caching, Xcode no longer needed to spend significant time indexing files, making the IDE feel noticeably more responsive. Builds became faster, and the everyday frustration of waiting on incremental builds greatly decreased.</p>
<img style="max-width: 600px" src="/marketing/images/blog/2024/12/16/trendyol/build-duration-graph.webp" alt="Build Time Graph for Trendyol iOS App">
<h2 id="the-approach" tabindex="-1" class="marketing__blog_post__body__content__heading">
The approach<a href="#the-approach" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The approach"></a></h2>
<p>
After speeding up compilation, we turned our attention to tests, which we could further optimize by running them selectively. At the time we started exploring this, Tuist had not yet shipped <a href="https://docs.tuist.dev/en/guides/develop/test/smart-runner">selective testing</a>, so we built a plugin leveraging <code class="inline">git diff</code> and <code class="inline">tuist graph</code> to identify only the modules affected by code changes. This allowed us to run a more focused set of unit and UI tests.</p>
<p>
Integrating selective testing with binary caching can be a game-changer. Here&#39;s how the two work together:</p>
<ol>
  <li>
<strong>Change detection:</strong> We identify which files and modules were changed since the last build.  </li>
  <li>
<strong>Targeted caching:</strong> Modules not impacted by the recent changes are retrieved from the Tuist cache. Instead of rebuilding everything, these modules reuse cached outputs.  </li>
  <li>
<strong>Significant time savings:</strong> After a month-long proof of concept, our build times were reduced by 65%. In controlled comparisons, setups with Tuist caching consistently outperformed those without it.  </li>
</ol>
<p>
This synergy between selective testing and binary caching dramatically improved developer productivity. Where we once faced slowdowns, we now had a seamless, accelerated workflow.</p>
<p>
Moving forward, we&#39;ll work closely with the Tuist team to integrate our solution with their selective testing feature. Their implementation, which relies on a more accurate change detection system based on file-system fingerprinting, will further enhance the precision and efficiency of our testing workflows.</p>
<img style="max-width: 600px" src="/marketing/images/blog/2024/12/16/trendyol/with-without-cache.webp" alt="With/Without Cache Comparison for Each Development MRs">
<h2 id="the-results" tabindex="-1" class="marketing__blog_post__body__content__heading">
The results<a href="#the-results" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The results"></a></h2>
<p>
From a developer&#39;s perspective, these enhancements have a tangible impact on everyday work. With selective testing and binary caching, developers spend less time waiting on builds and more time iterating on features or exploring solutions. Shorter feedback loops mean they can validate ideas quickly, focus on delivering quality, and better manage the complexities of a growing codebase without feeling slowed down by repetitive processes.</p>
<p>
For example, consider a developer looking to write and run UI tests. Thanks to Tuist&#39;s caching capabilities, generating and opening a clean Xcode environment and starting to run UI tests now takes around 30 seconds, an experience that would have been nearly impossible before, when the same process took at least 15 minutes for a project of this scale.</p>
<p>
Additionally, our CI build times have been reduced by 65%, decreasing from <strong>30 minutes to just 10 minutes</strong>. This significant improvement allows our CI pipelines to run faster, enabling quicker integrations and deployments.</p>
<blockquote>
  <p>
&quot;Our CI build times have been reduced by 65%, decreasing from 30 minutes to just 10 minutes.&quot;  </p>
</blockquote>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
Our Tuist instance is <a href="https://docs.tuist.dev/en/server/on-premise/install">self-hosted</a> within our internal infrastructure. This setup ensures ultra-fast cache transfers over our internal network and guarantees compliance with our security standards. As a result, we enjoy the performance benefits of caching without any external dependencies or potential security concerns.</p>
<p>
Our work with Tuist shows how investing in the right tools can lead to significant improvements in developer productivity and experience. We&#39;ll continue refining our strategies, exploring new techniques, and integrating with other testing methodologies. As we learn and evolve, we&#39;re committed to sharing our insights with the broader community.</p>
<blockquote>
  <p>
&quot;Tuist shows how investing in the right tools can lead to significant improvements in developer productivity and experience.&quot;  </p>
</blockquote>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Streamline previewing changes in your open source Swift apps – IcySky case study ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Use Tuist Previews in open source Swift apps to streamline testing latest changes for maintainers and contributors alike. ]]></summary>
      <link href="https://tuist.dev/blog/2024/11/25/tuist-previews-in-opensource"/>
      <id>https://tuist.dev/blog/2024/11/25/tuist-previews-in-opensource</id>
      <updated>Mon, 25 Nov 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
As mobile developers, we all understand the importance of testing latest changes as automated tests often fall short in catching UI and behavior-related issues. However, the current solutions for testing apps in PRs come with their own set of challenges. Tools like TestFlight, while powerful, have not been built with PRs in mind. Instead, they are focused for testing changes that have already been merged – critical metadata like commit SHA, branch name, and PR number are lost in the process.</p>
<p>
Additionally, TestFlight brings a lot of overhead to upload builds – such as going through the app review or having to sign the app in the PR workflows – which can be quite cumbersome for open source projects. This is where <a href="https://docs.tuist.dev/en/guides/features/previews">Tuist Previews</a> come in. They offer a streamlined way to test the latest changes in PRs, making it easier for maintainers and contributors alike.</p>
<p>
Recognizing the potential for open source apps, we partnered with <a href="https://github.com/Dimillian">Thomas Ricouard</a> and integrated Tuist Previews in the new <a href="https://github.com/Dimillian/IcySky">IcySky</a> app. IcySky can now benefit from all the features that Tuist Previews offer and we get to iterate with Thomas and IcySky&#39;s contributors to make Tuist Previews even better.</p>
<p>
  <img src="/marketing/images/blog/2024/11/25/tuist-previews-in-opensource/icysky-preview.gif" alt="Github PR comment">
</p>
<h2 id="contribute-by-testing-changes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Contribute by testing changes<a href="#contribute-by-testing-changes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Contribute by testing changes"></a></h2>
<p>
Let&#39;s consider a common scenario: a user raises an issue that they found in the app. A contributor creates a PR that <em>should</em> fix the issue. But does it really?</p>
<p>
Ideally, the issue author would test changes from the PR to confirm the issue is actually gone. But in most project, that would mean they&#39;d need to set up the development environment and build the app on their device. That can often be a cumbersome process, especially for newcomers. But with Tuist Previews, the PR includes a preview link with the app pre-built:</p>
<p>
  <img src="/marketing/images/blog/2024/11/25/tuist-previews-in-opensource/github-pr-comment.png" alt="Github PR comment">
</p>
<p>
Now, they can just click a link to see the changes on their simulator. The only prerequisite is to have Xcode and the <a href="https://docs.tuist.dev/en/guides/features/previews#tuist-macos-app">Tuist macOS app</a> installed. Contributors can then use the macOS app to test changes in multiple environments, such as iPhone or Apple TV:</p>
<img src="/marketing/images/blog/2024/11/25/tuist-previews-in-opensource/tuist-macos-app.png" width="300px" alt="Tuist macOS app screenshot">
<p>
And to make it easier to test the latest changes that have been merged to <code class="inline">main</code>, use a <code class="inline">README</code> badge to make the latest preview easily accessible by anyone:
<a href="https://tuist.dev/Dimillian/IcySky/previews/latest">  <img src="https://tuist.dev/Dimillian/IcySky/previews/latest/badge.svg" alt="Tuist Preview">
</a></p>
<p>
To see Tuist Previews in action, you can watch the following video:</p>
<iframe title="Running previews from a PR comment" width="560" height="315" src="https://videos.tuist.io/videos/embed/1eea415f-a2b1-4264-89a3-f64c7e2a3477" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="set-it-up" tabindex="-1" class="marketing__blog_post__body__content__heading">
Set it up<a href="#set-it-up" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Set it up"></a></h2>
<p>
Did the above pique your interest? Here&#39;s a few of steps to start using Tuist Previews in <em>your</em> open source project.</p>
<ol>
  <li>
<strong>Install the Tuist CLI</strong> – if you haven&#39;t already, <a href="https://docs.tuist.dev/en/guides/quick-start/install-tuist">install</a> the Tuist CLI.  </li>
  <li>
<code class="inline">tuist auth</code> – authenticate and create an account if needed. We recommend using GitHub for authentication which is required for some features.  </li>
  <li>
<code class="inline">tuist organization create {organization-name}</code> – it&#39;s recommended to create a Tuist organization unless you&#39;re working on a personal project. Run  to create one.  </li>
  <li>
<code class="inline">tuist project create {organization-name}/{project-name}</code> – create a new project in your organization. The full project handle follows the same convention as GitHub.  </li>
  <li>
Create a <code class="inline">Tuist.swift</code> file in the root of your project with the following content:  </li>
</ol>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let config = Config(
    fullHandle: &quot;{organization-name}/{project-name}&quot;
)    </shiki-highlight>
  </div>
</div>
<ol start="6">
  <li>
<code class="inline">tuist project update {organization-name}/{project-name} --repository-url {your-repository-url} --visibility public</code> – connect your Tuist project with the GitHub repository and make its visibility public to make it accessible to developers outside of your Tuist organization.  </li>
  <li>
<code class="inline">tuist project tokens create {organization-name}/{project-name}</code> – create a token for your project. This token will be used to authenticate with Tuist in your CI – copy this token and set it as a secret in your repository.  </li>
  <li>
Install the <a href="https://github.com/marketplace/tuist">Tuist GitHub app</a> in your repository to get <a href="https://docs.tuist.dev/en/guides/features/previews#pullmerge-request-comments">PR comments</a>.  </li>
  <li>
Add <code class="inline">tuist share NameOfYourApp --configuration Debug --platforms iOS</code> to your CI script to share a Tuist Preview. This needs to be done <em>after</em> you build the app. You can find an example of a CI script with <code class="inline">tuist share</code> in the <a href="https://github.com/Dimillian/IcySky/blob/6f1e92bc4a3f1b8c83f1e61230ebef7034dca142/.github/workflows/icy_sky.yml">IcySky repository</a>. Ensure that the CI steps with <code class="inline">tuist share</code> has the <code class="inline">TUIST_CONFIG_TOKEN</code> environment variable defined with the value from step 6.  </li>
  <li>
<a href="https://docs.tuist.dev/en/guides/features/previews#readme-badge">Add a badge</a> to your README, so that you and contributors can easily download the latest version.  </li>
</ol>
<p>
... and that&#39;s it – you have now made testing changes easier for maintainers, contributors, and users! All Tuist features are <strong>free for open source projects</strong>, so you can start using Tuist Previews today with no strings attached. To learn more about Tuist Previews, you can find our up-to-date <a href="https://docs.tuist.dev/en/guides/features/previews">documentation here</a>.</p>
<p>
Additionally, to see Tuist Previews in action, head over to the <a href="https://github.com/Dimillian/IcySky">IcySky</a> repository, including the <a href="https://github.com/Dimillian/IcySky/pull/3">PR</a> for the initial Tuist Preview support. <strong>Huge thanks to Thomas</strong> for taking the time to set everything up and give us feedback. It means a lot 💜</p>
<p>
And if <em>you</em> have feedback to share, we&#39;d love to hear from you at our <a href="https://community.tuist.dev/">community forum</a> 😌</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Optimizing compilation and test runs with Xcode projects ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Slow workspaces and long compilation times can hinder developer productivity. Learn how Tuist optimizes Xcode projects to improve performance and accelerate feature delivery. ]]></summary>
      <link href="https://tuist.dev/blog/2024/11/18/optimizing-compilation-and-test-runs-with-xcode-projects"/>
      <id>https://tuist.dev/blog/2024/11/18/optimizing-compilation-and-test-runs-with-xcode-projects</id>
      <updated>Mon, 18 Nov 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Xcode projects and workspaces can take a long time to compile in clean environments. The compilation time typically grows with the project, with periodic performance improvements due to hardware upgrades—a costly endeavor for organizations.</p>
<p>
Some developers normalize this as an inherent challenge of Apple native development. Others introduce dynamic runtimes like <a href="https://reactnative.dev/">React Native</a>, which can hot-reload code and skip most compilation cycles. Some organizations even consider absorbing the cost of replacing Xcode&#39;s build system.</p>
<p>
For years, we have invested in solving this challenge using the most native and cost-effective approach possible through Xcode primitives. <strong>We believe that unproductive development environments can negatively impact organizational productivity and the quality of shipped applications. Our goal is to help organizations prevent such inefficiencies.</strong></p>
<p>
In this blog post, I&#39;ll share how Tuist addresses these challenges and the potential impact on your projects. Let&#39;s begin by discussing project graphs.</p>
<h2 id="your-project-is-a-graph" tabindex="-1" class="marketing__blog_post__body__content__heading">
Your Project is a Graph<a href="#your-project-is-a-graph" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Your Project is a Graph"></a></h2>
<p>
Your project forms a compilation graph that the editor uses to provide a coding experience and that the build system uses to generate build products. Traditionally, this graph was statically codified in <code class="inline">.pbxproj</code> and peripheral files like <code class="inline">.xcconfig</code> or test plans. The build could be dynamically configured during operations like build or test.</p>
<p>
This landscape changed with the introduction of Swift Package Manager (SPM). Suddenly, projects gained references to another graph—the package graph—which was dynamically generated by SPM and reconciled at build-time with closed-source code.</p>
<p>
How can we optimize this? Simply put, we need to skip compilation steps in the graph. However, Xcode&#39;s build system doesn&#39;t allow direct manipulation of internal graph processing, unlike build systems like Gradle.</p>
<p>
You can add tasks to the graph via build phases or SPM plugins, but what&#39;s truly desired is a function that takes a graph as input and returns an optimized graph output. The image below captures this concept:</p>
<div style="text-align: center;">
  <img src="/marketing/images/blog/2024/11/18/optimizing-compilation-and-test-runs-with-xcode-projects/optimized-graph.png" style="width: 30vw;"/></div>
<p>
If optimizations were this straightforward, Apple would have implemented it already. To understand why it hasn&#39;t happened, we need to discuss <strong>hermeticity</strong>.</p>
<h2 id="hermeticity-in-xcode-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Hermeticity in Xcode Projects<a href="#hermeticity-in-xcode-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Hermeticity in Xcode Projects"></a></h2>
<p>
Bazel effectively demonstrates the importance of <a href="https://bazel.build/basics/hermeticity">hermeticity</a> in build systems. In essence, hermeticity means a build system should produce identical output given the same input, regardless of the execution environment. This enables artifact caching and sharing across different machines—a critical feature in distributed systems.</p>
<p>
However, Xcode&#39;s build system lacks hermeticity. Examples that break hermeticity include:</p>
<ul>
  <li>
Implicit dependencies relying on heuristics rather than explicit declarations  </li>
  <li>
Shared caches like derived data that can cause varying build behaviors  </li>
  <li>
Dependencies on external states like environment variables, system files, or user-specific configurations  </li>
  <li>
Non-hermetic scripts dependent on external commands with unpinned versions  </li>
</ul>
<p>
Hermeticity isn&#39;t just about build optimization—it&#39;s crucial for making incremental builds more deterministic and improving features like <a href="https://developer.apple.com/documentation/swiftui/previews-in-xcode">SwiftUI previews</a>. If the editor cannot determine the relationship between a change and the binary graph, previews simply won&#39;t work.</p>
<p>
Optimizing Xcode projects would require Xcode to evolve its graph toward encouraging hermeticity and discouraging implicit configurations. While <a href="https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies">Explicit Modules</a> represent a step in this direction, significant progress remains ahead.</p>
<h2 id="encouraging-explicitness-and-mutating-the-graph" tabindex="-1" class="marketing__blog_post__body__content__heading">
Encouraging Explicitness and Mutating the Graph<a href="#encouraging-explicitness-and-mutating-the-graph" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Encouraging Explicitness and Mutating the Graph"></a></h2>
<p>
Tuist introduces a Swift DSL for declaring project graphs. When users define their projects, they&#39;re essentially mapping out the module graph. The <code class="inline">tuist generate</code> command transforms this graph into an Xcode workspace and projects.</p>
<p>
This subtle capability is key to project optimization. By generating Xcode workspaces and projects, we can optimize them during the generation phase.</p>
<p>
While we can&#39;t completely solve hermeticity, we can encourage it through our APIs, particularly at the dependency level. By designing APIs that promote explicit dependency declarations, we can mitigate non-hermetic behaviors.</p>
<p>
Our approach offers several advantages:</p>
<ul>
  <li>
Graph mutation using native Xcode project and target primitives  </li>
  <li>
A language that discourages non-hermetic configurations  </li>
  <li>
Utilizing XCFrameworks as compilation units  </li>
</ul>
<h2 id="caching-and-selective-test-execution" tabindex="-1" class="marketing__blog_post__body__content__heading">
Caching and Selective Test Execution<a href="#caching-and-selective-test-execution" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Caching and Selective Test Execution"></a></h2>
<p>
By constructing a <a href="https://en.wikipedia.org/wiki/Merkle_tree">Merkle Tree</a> that changes when a target changes, we can create unique identifiers for each target. This enables powerful workflows:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Cache all cacheable targets
tuist cache

# Generate projects reusing cached binaries
tuist generate 
tuist build
tuist test    </shiki-highlight>
  </div>
</div>
<p>
Tuist also introduces selective test execution. By persisting tests at the target level with associated hashes, the system can determine whether tests need re-execution.</p>
<h2 id="accelerating-feature-delivery" tabindex="-1" class="marketing__blog_post__body__content__heading">
Accelerating Feature Delivery<a href="#accelerating-feature-delivery" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Accelerating Feature Delivery"></a></h2>
<p>
The combination of selective test execution and caching can yield significant CI improvements—up to 70% and beyond. Developers can optimize their Xcode projects without costly build system replacements or platform abstractions.</p>
<p>
By declaring projects using a Swift DSL, teams can achieve optimizations, cleaner project structures, and more reliable Xcode performance. The impact on team productivity and business value delivery can be substantial.</p>
<p>
Interested in learning more? <a href="https://cal.tuist.io/team/tuist/tuist">Schedule a call with the Tuist team</a> for a comprehensive walkthrough.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Expanding the Apple Ecosystem: open and accessible developer tooling beyond official tools ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We’re on a mission to make developer tooling outside of Apple’s official tools more open and accessible. Through fair pricing, community-driven features, and language support, Tuist empowers developers to enhance their workflows and build better apps without barriers. Join us in expanding the ecosystem with accessible, community-driven extensions for all. ]]></summary>
      <link href="https://tuist.dev/blog/2024/11/08/accessible-tools"/>
      <id>https://tuist.dev/blog/2024/11/08/accessible-tools</id>
      <updated>Fri, 08 Nov 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
As we keep pushing to give Apple’s official tools new superpowers and fill the gaps in the developer experience, it’s clear just how essential it is for Tuist to be accessible to every developer and organization. What does that mean?</p>
<p>
First, we need to meet developers where they are. If you prefer using <a href="https://brew.sh">Homebrew</a> to install Tuist, we&#39;ll make it an official installation method. If you work with <a href="https://github.com/fastlane/fastlane">Fastlane</a>, there will be a lane that seamlessly integrates Tuist. And most importantly, if you’re working on an Xcode project and want to introduce Tuist without overhauling your workflow, we’ll make that easy for you, too.</p>
<p>
Accessibility also means breaking down language barriers. In many parts of the world, language can be a hurdle, and we don’t want that to stand between developers and Tuist. We’re <a href="https://community.tuist.io/t/our-documentation-is-now-localizable/94">committed to creating resources in multiple languages</a>, fostering local communities, and helping developers everywhere learn how to scale Swift app development with Tuist. <strong>Communities have brought us this far, and we’re dedicated to giving back and nurturing these connections.</strong></p>
<h2 id="pricing-that’s-accessible:-open,-fair,-and-transparent" tabindex="-1" class="marketing__blog_post__body__content__heading">
Pricing that’s accessible: open, fair, and transparent<a href="#pricing-that’s-accessible:-open,-fair,-and-transparent" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Pricing that’s accessible: open, fair, and transparent"></a></h2>
<p>
But accessibility goes beyond tools and language. Pricing plays a crucial role, and it’s something we need to address today. All around us, we see a trend of closed, one-on-one negotiated pricing models, restrictive demo versions, and opaque pricing tactics that sales reps often leverage through fear. We believe this inaccessibility is detrimental, and we want to be part of changing that norm.</p>
<p>
Everyone should have access to tools that enable faster, better app development, no matter their background or financial situation. <strong>If you&#39;re an indie developer just starting out, you shouldn’t have to pay for features that could significantly improve your daily work and app quality.</strong> It’s as simple as that. If we truly want to impact the ecosystem, we must ensure that everyone in it can access the tools that make this possible. We’re not a traditional sales-driven company—we’re here to empower, not exploit.</p>
<p>
Our business model is straightforward:</p>
<ul>
  <li>
Through usage measurement, payments reflect the value derived from the tool.  </li>
  <li>
Thanks to large enterprises, we can afford to keep costs low or even free for indie developers and small startups.  </li>
  <li>
We’re committed to open-sourcing more, driving innovation, and enabling use cases we can’t even imagine today.  </li>
</ul>
<h2 id="join-us-in-reversing-this-trend" tabindex="-1" class="marketing__blog_post__body__content__heading">
Join us in reversing this trend<a href="#join-us-in-reversing-this-trend" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Join us in reversing this trend"></a></h2>
<p>
If you share our mission of promoting accessible and sustainable tools in the Apple ecosystem, we’d love to collaborate with you.</p>
<p>
If you&#39;re an organization or developer paying a hefty price for a valuable service with a pricing model you find unfair, or if there’s a tool you wish you could add to your setup without going through sales hurdles, let us know at <a href="mailto:contact@tuist.dev">contact@tuist.dev</a>.</p>
<p>
<strong>Our team will work with you to develop the feature, and in return, you’ll get lifetime access to it—yes, free forever, as long as there are no high underlying costs of infrastructure.</strong> Together, we’ll build something that’s more accessible for the entire ecosystem, and you’ll benefit from it at no cost.</p>
<p>
Where possible, we’ll aim to make the client-side code open source, creating a commodity for the community, while the server side enhances the tool and sustains Tuist. You win, we win, and the ecosystem wins.</p>
<p>
Deal? Let’s make the Apple ecosystem a more accessible, inclusive place for everyone.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Speed up your Xcode CI workflows for free ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Discover how to significantly speed up your Xcode CI workflows without spending a dime. Learn about common challenges and how Tuist can help you overcome them, improving your development process and productivity. ]]></summary>
      <link href="https://tuist.dev/blog/2024/11/07/faster-xcode-workflows-for-free"/>
      <id>https://tuist.dev/blog/2024/11/07/faster-xcode-workflows-for-free</id>
      <updated>Thu, 07 Nov 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
It’s Monday. You show up to work, grab a coffee, attend the morning standup, and then you’re tasked with fixing a few minor design inconsistencies in the app you’re working on. &quot;This should take five minutes,&quot; you think.</p>
<p>
In a few moments, you have the fix ready in <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>. You run linters, format the code, and prepare a PR for review.</p>
<p>
But then CI kicks in. The 100-module project needs to compile – and only after building the 30 external packages and parsing the <a href="https://github.com/swiftlang/swift-syntax">SwiftSyntax</a> tree for dependencies. Fifteen minutes pass, and the project is still compiling. You scroll through Mastodon, make a latte, and come back half an hour later, expecting to see a green checkmark. But <strong>CI is red</strong>. Flaky tests strike again.</p>
<p>
You don’t have the time (or the context) to dig into the flakiness, so you hit retry, check your emails, read a new Swift newsletter, and follow some rants about Swift&#39;s concurrency model. Finally, CI is green. But wait – there’s a conflict in <code class="inline">.pbxproj</code> because another PR was merged while you were away. Fixing that will take another 30 minutes.</p>
<p>
After 1.5 hours, you get the green checkmark and can merge your PR. The five-minute task has taken over an hour. Welcome to Xcode development.</p>
<h2 id="leadership-weighs-in" tabindex="-1" class="marketing__blog_post__body__content__heading">
Leadership weighs In<a href="#leadership-weighs-in" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Leadership weighs In"></a></h2>
<p>
This is happening more often. Eventually, leadership asks questions. During your 1:1, your manager raises an important topic: <a href="https://reactnative.dev/">React Native</a>.</p>
<p>
Leadership is concerned about the iOS team’s velocity compared to the web and Android teams, who adopted <a href="https://gradle.com/develocity/">Develocity</a>. As the team lead, you’re asked to weigh the costs and benefits of adopting React Native or other tools to catch up.</p>
<p>
The team is skeptical about React Native. They’ve heard of companies that adopted it only to regret it, with valuable engineering resources diverted to support the migration. The app relies heavily on platform-specific features that would be cumbersome to handle in a cross-platform setup. In other words, enthusiasm is low.</p>
<p>
At some point, you remember hearing about <a href="https://bazel.build/">Bazel</a> at a conference. It replaces Xcode’s build system, caches steps, and runs tests selectively. But setting it up is complex and maintaining it could strain your team’s resources. You’ve also heard of companies reverting their Bazel setups because the people who implemented them left. Not ideal.</p>
<p>
Migrating to SPM? Perhaps, but after reading <a href="https://medium.com/bumble-tech/scaling-ios-at-bumble-6f0602682903">Bumble’s blog</a>, you see that it introduces its own challenges. React Native starts to look like the most viable option, despite the cost.</p>
<h2 id="there-must-be-a-better-way" tabindex="-1" class="marketing__blog_post__body__content__heading">
There must be a better way<a href="#there-must-be-a-better-way" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to There must be a better way"></a></h2>
<p>
This is a common scenario in the <a href="https://community.tuist.io">Tuist community</a>. Teams are frustrated with Xcode’s implicit configuration and the complications of managing a large build graph. Many try SPM, but this just adds another build graph to maintain. Sticking to the “Apple way” doesn’t always help either.</p>
<p>
Xcode and Xcode projects are legacies. When configured well, they can be powerful tools for development. However, decisions made for convenience years ago now limit productivity, like linking binaries implicitly from system directories. It’s convenient – until it breaks and you’re waiting on a new Xcode update to fix it.</p>
<p>
If only the build system were more explicit and flexible. This is where Tuist comes in. We might be new to you, but let me tell you: you can reduce these headaches for free. <a href="https://www.youtube.com/watch?v=s9bqf01gciA&list=PLfCiO1zYKkAStEDxfttXZy4EJlPON4kYm&index=15">Trendyol</a> cut CI times by 70% by adopting Tuist, which improved developer happiness by making it easier to manage the project graph.</p>
<p>
Giving Tuist a try could save you hours. While not widely talked about, it’s an <a href="https://github.com/tuist/tuist">open-source solution</a> developed over seven years, trusted by large organizations to deliver software faster.</p>
<h2 id="getting-started-with-tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting started with Tuist<a href="#getting-started-with-tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting started with Tuist"></a></h2>
<p>
Defining your project with Tuist’s Swift DSL feels natural and intuitive. The APIs mirror Xcode’s terminology, abstracting complex parts like linking dependencies and mapping build settings. Migrating the project only takes a week, and suddenly, builds are 20% faster – just from a cleaner, more explicit configuration.</p>
<p>
Even LLDB, which had been flaky, starts working smoothly. And best of all, team members can now add or remove modules as needed. The platform team finally has a foundation for defining architecture and rules, giving everyone a productive development environment.</p>
<h2 id="speeding-up-compilation-and-testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Speeding Up Compilation and Testing<a href="#speeding-up-compilation-and-testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Speeding Up Compilation and Testing"></a></h2>
<p>
Remember the original problem of waiting 1.5 hours to merge a simple fix? While Tuist minimizes conflicts, flaky tests and slow compilation times remain issues. But Tuist has solutions for these too, without replacing Xcode or adding the complexity of cross-platform tools like React Native.</p>
<p>
By signing up with <code class="inline">tuist auth</code>, creating a project with <code class="inline">tuist projects create</code>, and configuring your CI pipeline to use <code class="inline">tuist cache</code>, you enable caching for external Swift packages. In CI, Tuist reuses binaries, reducing those 30-minute waits to about five minutes. Tuist even caches test results, so only relevant tests run after code changes. It feels like magic.</p>
<h2 id="going-further-with-metrics-and-tripwires" tabindex="-1" class="marketing__blog_post__body__content__heading">
Going further with metrics and tripwires<a href="#going-further-with-metrics-and-tripwires" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Going further with metrics and tripwires"></a></h2>
<p>
Flakiness, cache inefficiencies, or bundle size increases can still arise. Tuist has built-in metrics and tripwires to prevent regressions. At the end of each run, you get a URL with a detailed project report:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist build
# ...some logs
Results: https://tuist.dev/tuist/tuist/runs/592368    </shiki-highlight>
  </div>
</div>
<h2 id="use-it-for-free" tabindex="-1" class="marketing__blog_post__body__content__heading">
Use it for free<a href="#use-it-for-free" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Use it for free"></a></h2>
<p>
If these challenges sound familiar, consider giving Tuist a try. Our advanced features are available under a <a href="/pricing">free tier</a>, and you can explore with a small project by running tuist init. Even our team uses Tuist daily, leveraging Xcode projects to their fullest potential.</p>
<p>
If you’d like to see Tuist in action, have questions, or want to discuss how it could transform your project, schedule a call with us. We’d love to help.</p>
<p>
If you would like to see it live, ask us questions, or walk you through how Tuist could impact your project,
you can <a href="https://cal.tuist.io/team/tuist/tuist">schedule a call with us</a> and we&#39;ll gladly help you.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Designing the new Tuist brand & website ]]></title>
      
      
      <author>
        <name><![CDATA[ Silvia ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Discover how we transformed the Tuist website into a vibrant digital experience that aligns with their open-source philosophy and product innovation. ]]></summary>
      <link href="https://tuist.dev/blog/2024/11/06/designing-tuist-website"/>
      <id>https://tuist.dev/blog/2024/11/06/designing-tuist-website</id>
      <updated>Wed, 06 Nov 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
We&#39;re excited to share this post written by the talented team at <a href="https://www.guindastudio.com">Guinda Studio</a>, who helped us transform our website into what it is today. They did an amazing job capturing our vision and values while creating a unique digital experience. Below, they share their perspective on the journey of redesigning the Tuist website.</p>
<h2 id="innovation-through-an-open-source-philosophy" tabindex="-1" class="marketing__blog_post__body__content__heading">
Innovation through an Open Source Philosophy<a href="#innovation-through-an-open-source-philosophy" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Innovation through an Open Source Philosophy"></a></h2>
<p>
Tuist challenged us to create a unique and distinctive website for their product, one that aligns with the open-source philosophy of the project and its community. This approach, championed by its creators, <a href="https://fosstodon.org/@pedro@mastodon.pepicrft.me">Pedro Piñera</a> and <a href="https://fosstodon.org/@marekfort@mastodon.online">Marek Fořt</a>, promotes shared responsibility and invites contributions for continuous improvement. Moreover, they view joy as the driving force behind their product, paying attention to details with the goal of creating simple yet powerful emotional experiences. As product designers, how could we not want to contribute? Let’s dive in!</p>
<h2 id="build-better-apps-faster" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build Better Apps Faster<a href="#build-better-apps-faster" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build Better Apps Faster"></a></h2>
<p>
Now, what exactly is Tuist? This was one of the main insights we needed to address, as it is a product for developers, thus very technical in terminology and functionalities. It had to be understandable so that anyone visiting the website could grasp its benefits and advantages before considering its adoption.</p>
<p>
Tuist is a platform designed to enhance developers&#39; productivity when building their products through key solutions such as Tuist Projects, Tuist Cache, Tuist Tests, and Tuist Runs.</p>
<p>
To further scale and evolve their product, they needed to connect these functionalities with potential clients, explaining to companies what needs they addressed and what these features entailed, in order to find their tailor-made solution plan.</p>
<p>
Ultimately, they were ready to elevate Tuist to a new level, but their website was not keeping pace with their product.</p>
<h2 id="a-design-that-evokes-orderly-emotions" tabindex="-1" class="marketing__blog_post__body__content__heading">
A Design that Evokes Orderly Emotions<a href="#a-design-that-evokes-orderly-emotions" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A Design that Evokes Orderly Emotions"></a></h2>
<p>
They required a distinctive design tailored to their product’s needs, evoking emotions in an attractive and powerful manner. Emotions that were measured and orderly, guiding and explaining the entire narrative of their product and philosophy.</p>
<p>
In a market context where all websites were homogeneous and repetitive, we had a significant opportunity to stand out.</p>
<p>
Our approach focused on two clear axes: firstly, giving a unique and distinctive personality to the Tuist brand, where a range of purples harmonized with powerful colors like lime and complementary shades, providing the dynamism and energy the brand required.</p>
<p>
Additionally, we created unique, clear, and simple illustrations to support the more technical content.</p>
<p>
Furthermore, we undertook exercises in visual hierarchy and storytelling to ensure all elements aligned with the product’s discourse and were on the same level.</p>
<p>
The result was accompanied by a Design System that has allowed Tuist to continue scaling and evolving its brand universe.</p>
<p>
  <img src="/marketing/images/blog/2024/11/06/designing-tuist-website/design.jpeg" alt="An image of the new design system in Figma">
</p>
<h2 id="connecting-the-product’s-purpose-with-the-brand" tabindex="-1" class="marketing__blog_post__body__content__heading">
Connecting the Product’s Purpose with the Brand<a href="#connecting-the-product’s-purpose-with-the-brand" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Connecting the Product’s Purpose with the Brand"></a></h2>
<p>
A brand&#39;s transformation is never-ending, just as we expect to continue seeing Tuist evolve and advance as a product.
Guinda Team</p>
<blockquote>
  <p>
Our marketing site design system is now publicly available in <a href="https://www.figma.com/community/file/1436003642379974190/tuist-website-design-system">Figma</a> and licensed under <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>. Feel free to use it as inspiration for your own projects!  </p>
</blockquote>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Our pricing philosophy ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn about the philosophy and model that guide our pricing decisions. ]]></summary>
      <link href="https://tuist.dev/blog/2024/11/05/our-pricing-philosophy"/>
      <id>https://tuist.dev/blog/2024/11/05/our-pricing-philosophy</id>
      <updated>Tue, 05 Nov 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
As we revamped our pricing page, we aimed to make it unique, transparent, and straightforward—quite different from the typical SaaS approach where pricing can feel like a guessing game. Many companies try to maximize what they can charge, but we take a different path, inspired by a &quot;pay-for-what-you-use&quot; philosophy. Just like a utility, everyone pays the same rates with no hidden markups. In this post, I’d like to unfold the philosophy behind that approach.</p>
<h2 id="our-principles" tabindex="-1" class="marketing__blog_post__body__content__heading">
Our principles<a href="#our-principles" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Our principles"></a></h2>
<p>
These are the principles that guide our pricing philosophy:</p>
<h3 id="1.-we-charge-per-usage" tabindex="-1" class="marketing__blog_post__body__content__heading">
1. We charge per usage<a href="#1.-we-charge-per-usage" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 1. We charge per usage"></a></h3>
<p>
Many traditional companies hide their prices behind a &quot;contact sales&quot; button, leveraging your lack of bargaining power to charge as much as possible. We believe that&#39;s unfair. Every company should pay the same rate based on usage. Put simply, if your organization is larger, you’ll likely use Tuist more and pay more than a two-person startup—no hidden fees, just straightforward, usage-based pricing.</p>
<h3 id="2.-you-don't-pay-if-you-don't-use-it-enough" tabindex="-1" class="marketing__blog_post__body__content__heading">
2. You don&#39;t pay if you don&#39;t use it enough<a href="#2.-you-don't-pay-if-you-don't-use-it-enough" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 2. You don't pay if you don't use it enough"></a></h3>
<p>
If you’re an indie developer or a small company that doesn’t use Tuist extensively, you don’t have to pay anything. We believe that’s fair—no financial barriers should stand in the way of using Tuist. We’re here to help people build better apps, and when you’re just starting out, you may not have the budget for costly tools. Don’t worry; with Tuist, you can get started without the expense.</p>
<h3 id="3.-we-aim-to-be-the-cheapest-at-every-scale" tabindex="-1" class="marketing__blog_post__body__content__heading">
3. We aim to be the cheapest at every scale<a href="#3.-we-aim-to-be-the-cheapest-at-every-scale" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 3. We aim to be the cheapest at every scale"></a></h3>
<p>
We want to be the cheapest and most transparent option in the Swift app development ecosystem. If you think we are not, please <a href="mailto:contact@tuist.dev">let us know</a>.</p>
<h2 id="our-model" tabindex="-1" class="marketing__blog_post__body__content__heading">
Our model<a href="#our-model" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Our model"></a></h2>
<p>
We’re a commercial open source company. We build open source software and develop paid extensions that fund even more open source development. Our open source and paid products are complementary—each provides value on its own, with no strings attached. If Tuist provides value to you, great! It’s free to use. If your usage grows, even better—we’re here to support you at scale. And if you decide it’s no longer the right fit, we’ve made it easy for you to move on.</p>
<p>
This model grew out of seeing too many companies burden customers with “contact sales” banners and choices that lock them into platforms. We wanted a different approach: transparency in our pricing, openness in our intentions, and a commitment to building something enduring. This model is our answer.</p>
<p>
Thanks to this model, we’ll keep building more open source tools for the Swift ecosystem and supporting local communities dedicated to creating better apps.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Introducing Tuist Ambassadors ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We are introducing the Tuist Ambassadors program to recognize the people who have been going above and beyond to help others in the community. ]]></summary>
      <link href="https://tuist.dev/blog/2024/10/29/tuist-ambassadors"/>
      <id>https://tuist.dev/blog/2024/10/29/tuist-ambassadors</id>
      <updated>Tue, 29 Oct 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Over the years building Tuist in the open,
we&#39;ve seen many people going above and beyond to help others in the community.
They played a crucial role in the growth of the project,
and helped us reach communities that we wouldn&#39;t have reached otherwise.
Tuist wouldn&#39;t be what it is today without them.</p>
<p>
So we want to give back to the community by <strong>recognizing these people and their contributions.</strong>
And we are doing so by introducing the Tuist Ambassadors program.</p>
<h2 id="what-is-the-tuist-ambassadors-program?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is the Tuist Ambassadors program?<a href="#what-is-the-tuist-ambassadors-program?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is the Tuist Ambassadors program?"></a></h2>
<p>
Once a year, <strong>we&#39;ll select a small group of Tuist Ambassadors</strong> who have been nominated by the community for representing Tuist, building bridges between the core team and all Tuisters, and leading by example in their own communities.</p>
<p>
Tuist Ambassadors become recognized leaders and advisors in the Tuist community and strong advocates for the values of the project. They are not only Tuist experts: they lead, support, and inspire others. They play a pivotal role in advancing our shared goals.</p>
<h2 id="what-are-the-benefits-of-being-a-tuist-ambassador?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are the benefits of being a Tuist Ambassador?<a href="#what-are-the-benefits-of-being-a-tuist-ambassador?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are the benefits of being a Tuist Ambassador?"></a></h2>
<ul>
  <li>
<strong>Visibility and recognition:</strong> You&#39;ll be recognized as a Tuist Ambassador on the Tuist website and in the project&#39;s communication channels. You&#39;ll get a special role in the community forum.  </li>
  <li>
<strong>One-of-a-kind Tuist swag:</strong> Ambassadors get our iconic Ambassador jacket and a custom patch for each Ambassador batch year.  </li>
  <li>
<strong>Access and influence:</strong> Ambassadors are more tightly integrated into the shaping process and have the ability to provide early feedback before releases are out. They also join periodic calls with the Tuist team to discuss roadmaps and provide feedback.  </li>
  <li>
<strong>Amplify Budget:</strong> Tuist supports Ambassadors who speak at external events, covering eligible expenses and providing other logistical support where appropriate.  </li>
</ul>
<h2 id="what-do-you-need-to-do-to-become-a-tuist-ambassador?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What do you need to do to become a Tuist Ambassador?<a href="#what-do-you-need-to-do-to-become-a-tuist-ambassador?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What do you need to do to become a Tuist Ambassador?"></a></h2>
<p>
The following criteria will be used to evaluate potential Tuist Ambassadors:</p>
<ul>
  <li>
Highly knowledgeable about Tuist - recognized expertise in the Tuist tech and able to articulate the benefits and vision behind Tuist.  </li>
  <li>
Have contributed to the Tuist project in a meaningful way, and/or is an active user of Tuist within their organization.  </li>
  <li>
Technical and direct tone, not &quot;salesy.&quot;  </li>
  <li>
Do not come across to other community members as pushing another product, service offering, or agenda.  </li>
  <li>
Regularly produce technical content for the community such as presenting on community calls or contributing a blog post (at least once every six months).  </li>
  <li>
Represent Tuist at public events such as meetups or industry events (at least once every six months).  </li>
  <li>
Actively help other Tuisters in the <a href="https://community.tuist.io">community forum</a>  </li>
  <li>
Provide feedback on Tuist features and releases  </li>
  <li>
Be a model Tuist Ambassador: respect our code of conduct, especially when critical of Tuist or defending Tuist against others&#39; criticism; remain respectful, constructive, and fair  </li>
</ul>
<h2 id="how-to-nominate-someone?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How to nominate someone?<a href="#how-to-nominate-someone?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How to nominate someone?"></a></h2>
<p>
The nominations for 2025 are now open. If you know someone who you think would be a great Tuist Ambassador, please fill out the <a href="https://opnform.com/forms/2025-tuist-ambassador-nomination-bojn4d">nomination form</a>.</p>
<br>
<p>
In January 2025 we&#39;ll announce the new Tuist Ambassadors.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Deploy your Swift on the Server apps with Kamal 2 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post, you'll learn how to use Kamal 2 to deploy your Swift on the Server apps to your own server. ]]></summary>
      <link href="https://tuist.dev/blog/2024/09/28/kamal-two-swift-server"/>
      <id>https://tuist.dev/blog/2024/09/28/kamal-two-swift-server</id>
      <updated>Sat, 28 Sep 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<a href="https://www.swift.org/">Swift</a> is an amazing language.
Developers use it not only for building apps for Apple platforms,
but also to run them <a href="https://swiftwasm.org/">on the browser</a> or <a href="https://www.swift.org/blog/embedded-swift-examples/">embedded systems</a>.
One of the platforms where developers were very excited to run Swift was the server.
This excitement led to the creation of frameworks like <a href="https://vapor.codes/">Vapor</a> and <a href="https://github.com/hummingbird-project/hummingbird">Hummingbird</a>,
a <a href="https://www.serversideswift.info/">conference</a>,
and even Apple evolved the language to introduce features that are key in building highly-concurrent web applications,
like <a href="https://developer.apple.com/tutorials/app-dev-training/managing-structured-concurrency">structured concurrency</a> and <a href="https://developer.apple.com/documentation/swift/actor">Actors</a>.
Did you know that the team behind <a href="https://culturedcode.com/things/">Things</a> uses it for <a href="https://x.com/ktosopl/status/1839664679720726839">server</a>?</p>
<p>
If you are new to using Swift on the server,
one of the things you&#39;ll have to figure out is <strong>how to and where deploy your app.</strong>
Historically, there has been many options to deploy your app.
Some large-scale organizations resorted to tools like <a href="https://kubernetes.io/">Kubernetes</a>,
which provided them with a lot of flexibility to deploy, scale, and manage their apps, and an independence from cloud providers.
However, Kubernetes is not the easiest tool to use.
So if you are a solo developer or a small team, you might want to look for something simpler.</p>
<p>
You could always get your own server, SSH into it, and manually set things up there,
but you want a system that is able to roll new versions out automatically ensuring there&#39;s no downtime.
This would be hard to achieve through a manual configuration.</p>
<p>
Simpler and an automatic alternative those models were using platforms like <a href="https://heroku.com">Heroku</a> or <a href="https://fly.io">Fly</a> that made it easy to deploy your app.
They made it as easy as running a <code class="inline">git push</code> or <code class="inline">fly deploy</code> command against them server.
Those platforms are often referred to as PaaS (Platform as a Service).
Their developer experience is top-notch, but since they sit between you and the infrastructure,
you might have to pay an extra cost for the convenience they provide.
What if the great DX could be achieved without that extra cost?
That&#39;s the question that the <a href="https://github.com/basecamp">Basecamp Team</a>,
in their process of moving away from the cloud,
asked themselves when they created <a href="https://kamal-deploy.org/">Kamal</a>.
They started referring to it as <em>#nopaas</em>.</p>
<h2 id="what-is-kamal?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is Kamal?<a href="#what-is-kamal?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is Kamal?"></a></h2>
<p>
Kamal is a Ruby-based CLI,
that can deploy containarized applications to your own SSH-accessible server.
All you need is an OCI-compliant (e.g. in a <code class="inline">Dockerfile</code>),
a registry to push and pull the image from,
and a server what can be accessed through SSH.
Kamal will take care of the rest with an intuitive and well thought-out CLI.</p>
<p>
Don&#39;t let the Ruby part scare you.
You don&#39;t need to know Ruby to use Kamal.
All the configuration is done through a very intuitive <a href="https://en.wikipedia.org/wiki/YAML">YAML</a>-based <a href="https://kamal-deploy.org/docs/configuration/overview/">configuration file</a>.</p>
<p>
In this post, we&#39;d like to guide you through the process of deploying a Swift on the Server app using Kamal to an infrastructure provider like <a href="https://www.hetzner.com/">Hertzner</a>.</p>
<h2 id="installing-kamal" tabindex="-1" class="marketing__blog_post__body__content__heading">
Installing Kamal<a href="#installing-kamal" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Installing Kamal"></a></h2>
<p>
The first thing you&#39;ll need to do is to install Kamal.
If you have a Ruby setup already, for example to run <a href="https://github.com/fastlane/fastlane">Fastlane</a>,
you can use Ruby&#39;s <code class="inline">gem install kamal</code> command to install it.
Alternatively, as suggested in <a href="https://kamal-deploy.org/docs/installation/">the documentation</a>,
you can run it through a container, which eliminates the need to have Ruby installed on your machine:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
alias kamal=&#39;podman run -it --rm -v &quot;${PWD}:/workdir&quot; -v &quot;/run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock&quot; -e SSH_AUTH_SOCK=&quot;/run/host-services/ssh-auth.sock&quot; -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/basecamp/kamal:latest&#39;    </shiki-highlight>
  </div>
</div>
<h2 id="create-a-server-on-hetzner" tabindex="-1" class="marketing__blog_post__body__content__heading">
Create a server on Hetzner<a href="#create-a-server-on-hetzner" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Create a server on Hetzner"></a></h2>
<p>
If you don&#39;t have a server yet, you can can create one on <a href="https://www.hetzner.com/cloud/">Hetzner</a> or any other provider that gives you SSH access.</p>
<p>
When you create a server, you&#39;ll be asked for the following information:</p>
<ul>
  <li>
<strong>Location:</strong> This will depend on where most of the request to your app will come from. In our case, we are going to select <code class="inline">eu-central</code> for the sake of this tutorial.  </li>
  <li>
<strong>Image:</strong> Select Ubuntu 20.04, although Kamal should work with other Linux distributions.  </li>
  <li>
<strong>CPU:</strong> Select the smallest one from either x86 or ARM64, which is enough for a small app.  </li>
  <li>
<strong>Networking:</strong> Select <em>Public IPv6</em>. Later on you can add a <em>Public IPv4</em> if you need.  </li>
  <li>
<strong>SSH keys:</strong> This is a very important part since it will allow you to access the server. If you don&#39;t have an SSH key yet, you can generate one following <a href="https://community.hetzner.com/tutorials/add-ssh-key-to-your-hetzner-cloud">this tutorial</a>.  </li>
</ul>
<p>
There are a handful of other options, from which we recommend you to enable backups in case you need to restore the server.
Then scroll down to the bottom, give it a name, which in our case will be <code class="inline">swift-on-server</code>, and click on <code class="inline">Create &amp; Buy Now</code>.
In a few seconds you&#39;ll have your server up and running with the IP addres to access to it.</p>
<p>
Make sure you can access to it by running:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Replacing /64 at the end with 1
# Example: ssh root@2a01:4f8:c013:44ae::1
ssh root@{ip-v6-address}    </shiki-highlight>
  </div>
</div>
<h2 id="create-a-swift-on-the-server-app" tabindex="-1" class="marketing__blog_post__body__content__heading">
Create a Swift on the Server app<a href="#create-a-swift-on-the-server-app" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Create a Swift on the Server app"></a></h2>
<p>
If you don&#39;t have a Swift on the Server app yet, you&#39;ll need to create one.
You can follow either <a href="https://docs.vapor.codes/getting-started/hello-world/">this tutorial</a> if you plan to use Vapor,
or <a href="https://docs.hummingbird.codes/2.0/documentation/hummingbird/gettingstarted">this other one</a> if you plan to use Hummingbird.</p>
<p>
Note that projects created by both frameworks include a <code class="inline">Dockerfile</code> (<a href="https://github.com/hummingbird-project/template/blob/main/Dockerfile">Hummingbird</a> and <a href="https://github.com/vapor/template/blob/main/Dockerfile">Vapor</a>) to build and run your apps.
This is a requirement for Kamal, so if your project doesn&#39;t have one, you&#39;ll need to create it using those as a reference.</p>
<p>
To make sure your app runs fine when containerized, you can run it locally:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# You can use Docker instead of Podman if you prefer
podman build -t swift-on-server .
podman run -p 8080:8080 swift-on-server --port 8080    </shiki-highlight>
  </div>
</div>
<p>
If those commands succeed, you should see a log indicating that the app is running in some port.</p>
<h2 id="adding-kamal-configuration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Adding Kamal configuration<a href="#adding-kamal-configuration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Adding Kamal configuration"></a></h2>
<p>
Once you have Kamal installed, a containarizable Swift on the Server app, and a server to deploy it to, you can start adding the Kamal configuration.
Create the file <code class="inline">config/deploy.yml</code> in your project with the following content:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
service: swift-on-server
image: my-user/swift-on-server
servers:
  - server-ip # Example: 2a01:4f8:c013:44ae::1
registry:
  username:
    - KAMAL_REGISTRY_USERNAME
  password:
    - KAMAL_REGISTRY_PASSWORD
builder:
  arch: arm64
proxy:
  app_port: 8080
  healthcheck:
    interval: 3
    path: /
    timeout: 3    </shiki-highlight>
  </div>
</div>
<p>
You&#39;ll have to create a file at <code class="inline">.kamal/secrets</code> with the following content to indicate the environment variables that Kamal will use to read the registry credentials:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
KAMAL_REGISTRY_USERNAME=$KAMAL_REGISTRY_USERNAME
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD    </shiki-highlight>
  </div>
</div>
<p>
By default, Kamal will use the <a href="https://hub.docker.com">hub.docker.com</a> registry to push and pull the image,
which is free for public images.
<a href="https://github.com/features/packages">GitHub</a> and <a href="https://digitalocean.com">DigitalOcean</a> also offer registries, so you can use them if you prefer ensuring that you set the <code class="inline">registry.server</code> URL in the configuration file.</p>
<p>
Once you have the configuration file in place, you can run the following command to set up the server and accessories:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
kamal setup    </shiki-highlight>
  </div>
</div>
<p>
Once the server is setup, you can deploy your app by running:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
kamal deploy    </shiki-highlight>
  </div>
</div>
<p>
Once the app is deployed, you can access it by visiting the IP address of the server in your browser.
Remember that for IPv6 addresses, you&#39;ll have to wrap them in square brackets. For example: <code class="inline">http://[2a01:4f8:c013:44ae::1]</code>.</p>
<p>
Isn&#39;t it awesome? 🤩 With a single command you can deploy new instances of your app without any downtime.
And not only that, you can use <code class="inline">kamal rollback</code> to roll back to a previeous version in case something goes wrong,
or <code class="inline">kamal app logs</code> to see the logs of the app in real-time.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
  INFO [6d6940ce] Finished in 0.758 seconds with exit status 0 (successful).
App Host: 2a01:4f8:c013:44ae::1
2024-09-28T08:25:29.458868573Z 2024-09-28T08:25:29+0000 info SwiftOnServer : [HummingbirdCore] Server started and listening on 0.0.0.0:8080
2024-09-28T08:25:29.730502401Z 2024-09-28T08:25:29+0000 info SwiftOnServer : hb.request.id=407b3450aeb404662cfade84f76b5afb hb.request.method=GET hb.request.path=/ [Hummingbird] Request
2024-09-28T08:25:57.302865171Z 2024-09-28T08:25:57+0000 info SwiftOnServer : hb.request.id=407b3450aeb404662cfade84f76b5afc hb.request.method=GET hb.request.path=/ [Hummingbird] Request
2024-09-28T08:25:57.356775404Z 2024-09-28T08:25:57+0000 info SwiftOnServer : hb.request.id=407b3450aeb404662cfade84f76b5afd hb.request.method=GET hb.request.path=/favicon.ico [Hummingbird] Request    </shiki-highlight>
  </div>
</div>
<h2 id="bonus" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bonus<a href="#bonus" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bonus"></a></h2>
<p>
As a natural next step, you might want to set up a domain to point to the IP address of the server,
and configure the Kamal proxy to provide HTTPs automatically for your app.
For the latter, all you need to do is to add the following lines to the <code class="inline">config/deploy.yml</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
yaml    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="yaml">
proxy:
  ssl: true
  host: my-swift-on-server.com    </shiki-highlight>
  </div>
</div>
<p>
With the above configuration, Kamal will automatically request a certificate from <a href="https://letsencrypt.org/">Let&#39;s Encrypt</a> and configure the proxy to serve your app through HTTPs.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
At Tuist we love simplicity and automation,
and we believe that Kamal embodies that spirit for deployments.
When you are getting started,
or even if you are at the size of a company like <a href="https://37signals.com/">37Signals</a>,
the company behind Kamal,
you might want to keep your infrastructure engineering and financial costs low without compromising the developer experience.
We belive Kamal is unique in striking that balance,
and can help you stay focused on what you do best: building your Swift on the Server app.</p>
<p>
Until next time 🚀</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Shall the Xcode plane land? ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Xcode becomes more powerful yet more unreliable as capabilities are added and projects grow. We explore the challenges of scaling development in Xcode and share some thoughts on how Apple could improve the developer experience. ]]></summary>
      <link href="https://tuist.dev/blog/2024/09/20/xcode-plane"/>
      <id>https://tuist.dev/blog/2024/09/20/xcode-plane</id>
      <updated>Fri, 20 Sep 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
You have an idea for an app—perhaps something for the exciting new <a href="https://developer.apple.com/visionos/">visionOS platform</a>. You open <a href="https://developer.apple.com/xcode/">Xcode</a>, the official development environment for Apple platforms, create a new project, hit run, and voilà, a &quot;Hello World&quot; is up and running in the simulator. That initial moment, from conceiving an idea to seeing it come to life, is crucial in keeping your motivation high. Apple has done a fantastic job making that process swift and seamless. But that first line of Swift code marks the beginning of a much longer journey, and as your app grows, the initial burst of enthusiasm can quickly fade as the complexity of development increases.</p>
<p>
At Tuist, we&#39;ve engaged with numerous developers and companies about their experiences scaling app development, particularly in the context of Xcode and its projects. These conversations have highlighted common challenges and patterns that arise as projects grow. While we&#39;ve shared insights within our <a href="https://slack.tuist.io">Slack community</a>, we believe it&#39;s important to reach a broader audience. Our goal is to equip developers and organizations with the knowledge to identify these challenges early and to provide a vision for how Apple could enhance the developer experience. But first, let&#39;s explore the topic of scaling.</p>
<h2 id="scaling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Scaling<a href="#scaling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Scaling"></a></h2>
<p>
It&#39;s true that if you&#39;re a solo developer working on a small app with just one target in your Xcode project, you might assume you won&#39;t encounter many challenges. However, you&#39;d be surprised to learn that these challenges can arise sooner than expected. The term “scale” doesn&#39;t have a strict definition; its meaning varies depending on the context. At Tuist, <strong>we think of scaling development as the process of ensuring that development remains enjoyable and productive, no matter the size of the app, project, or team involved.</strong> By decoupling these variables, you set the foundation for healthy, motivated teams, which often leads to better ideas—and ultimately, better apps.</p>
<p>
<em>Did you know that Ruby on Rails is designed to <a href="https://rubyonrails.org/doctrine#optimize-for-programmer-happiness">optimize for developer happiness</a>?</em> Apple takes a similar approach with Xcode, especially when you&#39;re just getting started. But as your project grows, the fun and ease of development can begin to fade. So, why does this happen? To understand this shift, we need to examine a principle that Apple consistently applies in its tools, and which we believe plays a key role in why things stop being fun after a certain point: convenience through implicitness.</p>
<h2 id="convenience-through-implicitness" tabindex="-1" class="marketing__blog_post__body__content__heading">
Convenience through implicitness<a href="#convenience-through-implicitness" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Convenience through implicitness"></a></h2>
<p>
Xcode and Xcode projects were once much simpler. Initially, there was only one platform to support: OSX. However, with the rise of open-source software and platforms like Git, the cost of producing software dropped, sparking an era of remarkable innovation. This innovation gave birth to new platforms, and as a result, Xcode and its projects had to evolve to meet the growing demands: sharing code, compiling a new programming language like Swift, supporting multiple platforms, and more. Managing such a vast ecosystem of app developers is no small feat, and Apple did an impressive job. They navigated the rapid pace of change while ensuring developers could transition smoothly.</p>
<p>
However, in addressing some of these challenges, Apple introduced a reliance on implicit behavior and side effects as part of the system&#39;s design. While this approach worked well in practice, it also created a form of technical debt that developers continue to bear—and which still surfaces in the design of newer tools and systems. This may sound abstract, but let&#39;s break it down and make things more concrete.</p>
<h2 id="sharing-code" tabindex="-1" class="marketing__blog_post__body__content__heading">
Sharing code<a href="#sharing-code" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Sharing code"></a></h2>
<p>
Sooner or later in the life of the project, you need to share code within your app, whether through frameworks or libraries you&#39;ve created to use with extensions, or to enforce access boundaries and improve your app&#39;s architecture. You&#39;ll also likely rely on third-party packages from other developers. You can think of your project as a <a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph">directed acyclic graph (DAG)</a>, where each node represents a module—often modeled by an Xcode target, like a library or framework. Now, here&#39;s the challenge: <strong>managing this graph is hard</strong>. Adding or removing a module can create ripple effects throughout the entire system. For example, a dynamic framework might require certain upstream targets to embed it, or transitive static symbols leaking through a dynamic module could force their Swift module interfaces to be exposed elsewhere in the graph.</p>
<p>
If this sounds too abstract, think of it this way: <em>you can&#39;t just drag and drop modules in and out of the project without consequences.</em> With one or two modules, you might get by, but as the graph grows, so does the complexity of the relationships between modules—and with it, the risk of breaking something. Some developers we&#39;ve spoken to have described this issue as “needing to learn how Xcode works.” But we don&#39;t think developers should have to. <strong>Modularization is a standard requirement in almost every project, and it should be simple by default.</strong></p>
<p>
Did you know that your project might compile successfully purely due to side effects from previous compilation steps? One of your targets might resolve an import from another target not because it&#39;s declared as a dependency, but because it was already present in derived data.</p>
<p>
Then there are the common questions developers face: <em>Should this module be static or dynamic? Should it be a framework or a library? Can this product type embed dynamic frameworks? And what about dynamic libraries? What are the implications of linking a static library transitively?</em> These are questions we ask ourselves frequently, and often have to answer by reverse-engineering Xcode-generated projects and validating outputs with App Store Connect. Surprisingly, this crucial knowledge—rarely discussed in depth—can have serious implications for your app, from runtime crashes to unnecessarily bloating its size.</p>
<p>
In this case, the convenience of implicitness manifests as longer build times or build errors. Implicitness, along with things like <a href="https://developer.apple.com/documentation/xcode/configuring-your-project-to-use-mergeable-libraries">mergeable libraries</a>, are additional variables that introduce build-time complexity and variability, which can not only impact build performance but also make certain features, like Swift Previews, work inconsistently.</p>
<h2 id="my-swift-previews-stopped-working" tabindex="-1" class="marketing__blog_post__body__content__heading">
My Swift previews stopped working<a href="#my-swift-previews-stopped-working" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to My Swift previews stopped working"></a></h2>
<p>
We&#39;ve seen countless developers give up on Swift Previews. At some point, their Previews simply stopped working, and they couldn&#39;t pinpoint why. While the exact causes are hard to determine—largely due to Xcode being closed-source—we can still make educated guesses about where the issue might be.</p>
<p>
Imagine you&#39;re working in the Xcode editor with a preview open, and you change a line of code, either in the preview or in the transitive code it depends on. The editor must figure out what needs to be compiled and when in order to refresh the preview. As you might imagine, the larger and more implicitly linked the project graph becomes, the more difficult this task is for Xcode, leading to inconsistencies. It&#39;s ironic that features like implicit linking and embeddable frameworks, which were designed for convenience, can also introduce frustrations. It&#39;s no surprise that Swift Previews tend to work more reliably with dynamic frameworks, which are more self-contained, compared to libraries that require additional exposure of Swift modules or headers.</p>
<p>
Our advice to teams has always been to make implicit dependencies explicit, eliminating variables that the build system would otherwise need to resolve, such as whether an embeddable framework should be static or dynamic, or whether an import Foo statement means the target intends to depend on <code class="inline">Foo</code>. Developers are often surprised when we recommend against using certain newly announced features. After all, who would expect these innovations to impact their projects negatively?</p>
<p>
That said, we&#39;re optimistic about the future. Xcode&#39;s build system, while it may need to take a few steps back to reassess the path forward, is in the process of laying a more solid foundation. This will support exciting, compiler-dependent features like Swift Macros, enabling them to truly shine. In a sense, <strong>Apple is fixing the plane while flying it—because the business demands it—but we believe that a strategic “landing” to gain perspective would greatly benefit the entire ecosystem in the long run.</strong></p>
<p>
If any of this still seems abstract or exaggerated, let&#39;s pause and examine a phenomenon we&#39;ve been observing for quite some time.</p>
<h2 id="spm-as-a-project-manager" tabindex="-1" class="marketing__blog_post__body__content__heading">
SPM as a project manager<a href="#spm-as-a-project-manager" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to SPM as a project manager"></a></h2>
<p>
Have you noticed developers turning to Swift Package Manager (SPM) as their project manager? While part of the motivation is the appeal of describing dependencies in Swift, we believe <strong>the real excitement comes from SPM&#39;s ability to propose an alternative way of defining a graph of modules.</strong> With SPM, you don&#39;t have to worry about whether something is static or dynamic (unless you want to) or if resources need to be bundled and copied. Like Tuist, SPM conceptually simplifies the complexity of linking, which naturally excites developers. Who wouldn&#39;t be? It&#39;s so appealing that many developers have tried replacing their Xcode projects entirely with SPM. Did Apple foresee this? Probably not. What seemed like a promising future for developers has turned into yet another challenge for Apple to tackle.</p>
<p>
Apple now faces the task of reconciling two languages for defining module graphs: the one implicitly and &quot;explicitly&quot; codified in Xcode projects, and the one explicitly defined in Swift Packages. We say &quot;explicitly&quot; in quotes because, unsurprisingly, implicit behavior has also made its way into SPM. For example, packages that depend on <code class="inline">XCTest</code> are automatically discovered by SPM, even when they extend or wrap APIs. Additionally, Apple has to juggle two different build processes that must integrate as seamlessly as possible with Xcode. As many developers have experienced, this hasn&#39;t gone as smoothly as hoped. Package resolution can sometimes fail, leaving Xcode in a strange state, or result in invalid resolution states that are hard to recover from.</p>
<p>
Xcode was originally designed with the assumption that all the information needed to code and build a project was contained within the Xcode project itself. But with the introduction of SPM, this assumption was upended. Now, the module graph is resolved asynchronously and communicated back to Xcode, which must adjust its UI accordingly. Reconciling these two approaches has been challenging and costly to maintain, making the system prone to regressions.</p>
<p>
Let&#39;s not forget that when you add a dependency, SPM tries its best to make sure it works in your project, even if that means sometimes passing flags to avoid over-optimizations that could cause compilation issues. While this ensures your project builds, it can come at the cost of increased app size.</p>
<p>
While we may not fully understand how Apple engineers manage to reconcile this internally, we recognize the complexity involved. Still, we remain optimistic: imagine if the time currently spent resolving these integration challenges could be redirected toward enhancing features. It&#39;s an exciting prospect, and we believe the groundwork being laid today will lead to a more streamlined and robust future for both Xcode and SPM.</p>
<h2 id="what-if-the-plane-could-be-landed?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What if the plane could be landed?<a href="#what-if-the-plane-could-be-landed?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What if the plane could be landed?"></a></h2>
<p>
Imagine for a moment that Apple could pause, step back, and simplify the existing complexities, rather than adding more systems and languages that need to be reconciled. What might that future look like? It&#39;s an intriguing question—one we think about a lot, and we&#39;d like to share our thoughts with you in this blog post. Admittedly, this vision is quite idealistic, and in reality, there are many factors beyond the technical that could make it difficult to achieve. But in a world where those obstacles didn&#39;t exist, here&#39;s what we&#39;d love to see:</p>
<h3 id="a-unified-graph-language" tabindex="-1" class="marketing__blog_post__body__content__heading">
A unified graph language<a href="#a-unified-graph-language" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A unified graph language"></a></h3>
<p>
This applies to both local and remote targets—we don&#39;t see a reason why there should be two separate systems. The need to reconcile them creates a problem that shouldn&#39;t exist in the first place. Ideally, the language used should be fast to evaluate and free from side effects. Is Swift the right choice for this? We&#39;re not sure. On one hand, being able to declare things in Swift is fantastic—it&#39;s one of the main reasons developers love the language. But on the other hand, side effects are inevitable, and they go against the principle of predictable behavior. Swift doesn&#39;t seem to enforce this strongly enough. Bazel developed its own language, <a href="https://bazel.build/rules/language">Startlark</a>, to avoid such issues—<em>could something similar be an option here?</em></p>
<h3 id="an-optimizable-build-system" tabindex="-1" class="marketing__blog_post__body__content__heading">
An optimizable build system<a href="#an-optimizable-build-system" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to An optimizable build system"></a></h3>
<p>
A build system should be hermetic, with steps that are cacheable. As codebases grow larger, especially with the increasing number of supported platforms, faster hardware can only do so much. The pace at which compilation times are slowing down far outstrips hardware improvements. We&#39;ve seen companies where CI turnaround times stretch to an hour—and no, it wasn&#39;t Meta. This could happen to any team if a small app becomes successful and evolves into a large, complex project.</p>
<h3 id="implicitness-as-an-invalid-state" tabindex="-1" class="marketing__blog_post__body__content__heading">
Implicitness as an invalid state<a href="#implicitness-as-an-invalid-state" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Implicitness as an invalid state"></a></h3>
<p>
Implicitness should never have been accepted as a valid state in Xcode projects, and it certainly shouldn&#39;t have carried over into SPM. The build system should enforce explicit declarations—if something isn&#39;t explicitly defined, the compilation should fail immediately. Developers shouldn&#39;t have to wait minutes only to get a &quot;framework not found&quot; error. The system should construct the graph, analyze it, and fail right away if something is wrong. Developers&#39; time is invaluable and shouldn&#39;t be wasted. And yes, this means rethinking how derived data stores build artifacts.</p>
<h3 id="default-to-automatic-static/dynamic-and-framework/library-decision" tabindex="-1" class="marketing__blog_post__body__content__heading">
Default to automatic static/dynamic and framework/library decision<a href="#default-to-automatic-static/dynamic-and-framework/library-decision" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Default to automatic static/dynamic and framework/library decision"></a></h3>
<p>
Developers shouldn&#39;t have to worry about whether something should be static or dynamic, or whether it should be a framework or a library. With knowledge of the module graph, the destination platform, and the build configuration, the build system should be able to make these decisions deterministically, while still giving users the option to take control when necessary. Apple already knows, for example, that iOS apps can&#39;t include dynamic libraries—so why put developers in the position of having to dig up this information and make these choices themselves?</p>
<p>
Apple has taken a step in this direction with <code class="inline">.automatic</code> linking in Swift Packages, but what about project modules? This is why we advocate for a unified language that spans both local and remote modules—it needs to be consistent across the board.</p>
<h3 id="atomic-output-products" tabindex="-1" class="marketing__blog_post__body__content__heading">
Atomic output products<a href="#atomic-output-products" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Atomic output products"></a></h3>
<p>
By making output products fully atomic, you enable developers to easily share artifacts that others can simply drag and drop into their projects—no fuss, and everything just works. You might be thinking, &quot;Isn&#39;t that already the case with XCFrameworks?&quot; It was definitely a step in the right direction, but it&#39;s not entirely atomic. For example, if a dynamic XCFramework links a Swift library statically and the symbols aren&#39;t private, you&#39;d have to distribute the transitive Swift modules separately because you can&#39;t include more than one <code class="inline">.swiftmodule</code> in an XCFramework.</p>
<p>
And what if someone shares a static pre-compiled binary with you that causes duplicated symbols or bloats your binary size? Ideally, Apple&#39;s system could detect this, wrap the static binary in a dynamic one, and ensure everything works smoothly.</p>
<h3 id="more-documentation" tabindex="-1" class="marketing__blog_post__body__content__heading">
More documentation<a href="#more-documentation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to More documentation"></a></h3>
<p>
We need more comprehensive documentation on the various product types (e.g., app, framework, library, extension), valid graph configurations—such as including extensions in apps—and addressing inconsistencies across platforms, which ideally should be eliminated. While this knowledge is currently codified in Xcode&#39;s “create target/project” template, it should be accessible elsewhere.</p>
<p>
Even better, a new language could reduce the need for extensive documentation. Instead of thinking in terms of “embed this framework into this bundle,” “make this target static,” or “share this dynamic framework with the extension,” developers could simply express it as, “my app has an extension, and they both share utilities in this module.” Wouldn&#39;t that align more closely with developers&#39; mental models?</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
<strong>It would be fantastic if Tuist&#39;s project generation feature were unnecessary. This would signal that Xcode&#39;s fundamentals have evolved to meet the current and future needs of companies and developers.</strong> We don&#39;t believe the solution is to replace Xcode&#39;s build system with another like Bazel. Instead, we&#39;d love to see Apple invest in enhancing the existing system. If communicated well, the community would understand that this may come with some initial pain, but ultimately lead to a more reliable and faster app-building experience—exciting more developers and enabling them to work more efficiently.</p>
<p>
Tuist, like <a href="https://cocoapods.org">CocoaPods</a> before it, had to adopt project generation because there were no better alternatives. While we will continue to support organizations in this way, we envision a future where we can evolve into an extension of the build system, adding extra capabilities through a server and database. We&#39;re already moving in that direction, but we also need to devote significant energy to managing and simplifying the complexity that exists in Xcode projects.</p>
<p>
We love Swift, but we also have a deep appreciation for <a href="https://elixir-lang.org/">Elixir</a> and <a href="https://www.erlang.org/">Erlang</a>. These languages demonstrate how modeling a problem space can significantly impact the simplicity of the solutions you create. Erlang&#39;s approach with processes is a prime example, and we believe <strong>Apple&#39;s ecosystem is ready for a language that can elevate Xcode to where it deserves to be.</strong></p>
<p>
Apple and the Xcode team, you&#39;ve done an incredible job. We admire Xcode and many of its features, which are ahead of many other editors. However, the current foundation limits some of that potential. <strong>So, shall we land that plane?</strong></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 4.26.0: GitHub integration and a new command to find implicit dependencies ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn more about the new features and improvements in Tuist 4.26.0. ]]></summary>
      <link href="https://tuist.dev/blog/2024/09/03/tuist-4260"/>
      <id>https://tuist.dev/blog/2024/09/03/tuist-4260</id>
      <updated>Tue, 03 Sep 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<a href="https://github.com/tuist/tuist/releases/tag/4.26.0">Tuist 4.26.0</a> is out, and we&#39;d like to share with you the new features and improvements that come with it.</p>
<h2 id="meeting-developers-where-they-are:-github-integration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Meeting developers where they are: GitHub integration<a href="#meeting-developers-where-they-are:-github-integration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Meeting developers where they are: GitHub integration"></a></h2>
<p>
One of the principles we embrace at Tuist is to meet developers where they are.</p>
<ul>
  <li>
We chose Swift over <a href="https://yaml.org/">YAML</a> for the manifest format because developers love writing in Swift. This choice also unlocks many possibilities that aren&#39;t achievable with YAML.  </li>
  <li>
We integrated with and aligned ourselves with the <a href="https://www.swift.org/documentation/package-manager/">Swift Package Manager</a> because it has become the standard for managing dependencies in the Swift ecosystem.  </li>
  <li>
We added support for <a href="https://docs.tuist.io/guides/develop/build/cache">binary caching</a> using Xcode project primitives instead of asking developers to change their build system.  </li>
</ul>
<p>
<strong>But where exactly are Xcode developers?</strong> While they spend a large portion of their time in Xcode, they also spend significant time on platforms like <a href="https://github.com">GitHub</a> or <a href="https://slack.com">Slack</a>, collaborating with their peers. <strong>Should we meet them there?</strong> We think so!</p>
<p>
Traditionally, meeting developers on these platforms meant teams had to develop and maintain complex CI workflows that pushed data to these platforms. Although this approach worked, it exposed organizations to malicious actors because secrets were often revealed in CI workflows. Furthermore, the absence of a place to store data over time limited what teams could do with these integrations. <strong>Imagine being notified when a pull request introduces a regression in build times</strong> or <strong>when a newly introduced test in the codebase is flaky.</strong></p>
<p>
At Tuist, we had the most crucial element to enable this type of developer experience: <a href="https://docs.tuist.io/server/introduction/why-a-server">a server</a> that persists information from your projects and runs over time. However, we were missing one key piece—the integration of our server with one of the platforms where developers spend most of their time, <a href="https://github.com">GitHub</a>. That’s why we’re excited to announce that Tuist now integrates with GitHub. With a simple command, you can connect your remote project with a GitHub repository.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist project update tuist/tuist --repository-url https://github.com/tuist/tuist    </shiki-highlight>
  </div>
</div>
<p>
You also need to install the <a href="https://github.com/marketplace/tuist">Tuist GitHub app</a> in your repository.</p>
<p>
Once you integrate with GitHub, Tuist can automatically post your test results and previews that you can run with <a href="/blog/2024/08/28/tuist-macos-app">a single click</a>.</p>
<p>
  <img src="/marketing/images/blog/2024/09/03/tuist-4.26.0/github-app-comment.png" alt="A screenshot that shows a GitHub comment with some links to run previews and the results from running tests">
</p>
<h2 id="implicit-dependencies:-developers'-worst-nightmare" tabindex="-1" class="marketing__blog_post__body__content__heading">
Implicit dependencies: Developers&#39; worst nightmare<a href="#implicit-dependencies:-developers'-worst-nightmare" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Implicit dependencies: Developers' worst nightmare"></a></h2>
<p>
Xcode can resolve dependencies implicitly. Imagine this scenario: a developer adds the following line to a source file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import Network    </shiki-highlight>
  </div>
</div>
<p>
Suddenly, the module containing that source file depends on Network. This seemingly small change is a frequent cause of build-time slowness and Xcode instability. Implicit dependencies introduce new variables that must be resolved, not only during the build process but also while editing—when you&#39;re trying to load SwiftUI previews or get LLDB to work. In other words, Xcode&#39;s editor and build system are unexpectedly faced with new questions that need quick, reliable, and deterministic answers. And this isn&#39;t something that&#39;s widely discussed.</p>
<p>
Unfortunately, Tuist can&#39;t fix this issue due to how Xcode builds artifacts. However, many organizations that adopt Tuist report improved build times. This isn&#39;t because of Tuist itself but because the process of adopting Tuist often involves reviewing the dependency graph and converting implicit dependencies into explicit ones. Our frequent advice is to embrace explicitness as much as possible and remove uncertainties from the build system.</p>
<p>
Since we can&#39;t configure Xcode&#39;s build system to disallow implicit dependencies and tweaking build settings didn&#39;t produce the desired results, we decided to add a new command that uses static code analysis to catch implicit dependencies. It won&#39;t catch every instance, but it will identify many of them. We hope this command helps you detect implicit dependencies early in your development process.</p>
<p>
If you have a Tuist project, you can use the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist inspect implicit-imports    </shiki-highlight>
  </div>
</div>
<p>
The command will output any implicit imports it finds and fail if any are detected. Magic 🪄, right? Special thanks to <a href="https://github.com/rofle100lvl">Gorbenko Roman</a> for leading the development of this feature. He&#39;s already planning an even tighter integration with Xcode.</p>
<h2 id="other-changes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other changes<a href="#other-changes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other changes"></a></h2>
<ul>
  <li>
<a href="https://github.com/hiltonc">Hilton Campbell</a> <a href="https://github.com/tuist/tuist/pull/6663">added support</a> for detecting when dependencies are outdated and a <code class="inline">tuist install</code> is required.  </li>
  <li>
<a href="https://github.com/hiltonc">Hilton Campbell</a> also <a href="https://github.com/tuist/tuist/pull/6675">fixed</a> a bug that caused false positives reporting side effects with static dependencies.  </li>
</ul>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
We are working on a new website, which we plan to release soon, and we are starting to work on <a href="https://docs.tuist.io/guides/develop/automate/workflows">Tuist Workflows</a> and Swift-based automation solution that blurs environments, decouples organizations from proprietary CI YAMLs, and takes a CLI-first approach to automation. We expect the infrastructure and technology work required to enable this feature to be the foundation for many other features in the future.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ From a URL click to a running app preview: Introducing the Tuist macOS app ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We've released a Tuist macOS app as the next step in making sharing your apps a joyful experience. ]]></summary>
      <link href="https://tuist.dev/blog/2024/08/28/tuist-macos-app"/>
      <id>https://tuist.dev/blog/2024/08/28/tuist-macos-app</id>
      <updated>Wed, 28 Aug 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
A few weeks ago, we <a href="/blog/2024/08/06/url-centric-collaboration">announced</a> our first feature designed to make collaboration more efficient, <strong>Tuist Previews</strong>, and it was met with enthusiasm from teams who loved it 💜. But we knew there was room for improvement. From the start, our vision for previews was to make opening a preview link as effortless as clicking any link you find on the internet or receive from a colleague. This seamless experience is made possible on the macOS platform through a feature called <a href="https://developer.apple.com/ios/universal-links/">Universal Links</a>, which requires a dedicated macOS app to handle these links. The missing piece? A macOS app for Tuist.</p>
<p>
Today, we are excited to announce that the Tuist app for macOS is finally here!</p>
<p>
  <img src="/marketing/images/blog/2024/08/28/tuist-macos-app/menu-bar-app.png" alt="Screenshot of the Tuist macOS menu bar app">
</p>
<p>
<a href="https://tuist.dev/download">Download the app</a></p>
<em>  The macOS app is inspired by [Shopify&#39;s
  Tophat](https://github.com/Shopify/tophat), but is tightly integrated in the
  Tuist platform, requiring no additional configuration.</em><h2 id="how-the-tuist-app-streamlines-the-tuist-previews-flow" tabindex="-1" class="marketing__blog_post__body__content__heading">
How the Tuist app streamlines the Tuist Previews flow<a href="#how-the-tuist-app-streamlines-the-tuist-previews-flow" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How the Tuist app streamlines the Tuist Previews flow"></a></h2>
<p>
Until now, you would share and run Tuist Previews exclusively with the CLI:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist share Wikipedia --platforms iOS --configuration Debug
tuist run https://tuist.dev/tuist/wikipedia/previews/0191984a-8d33-754d-806b-bfecfd65f1c9    </shiki-highlight>
  </div>
</div>
<p>
Clicking on the Preview link wouldn&#39;t do anything. This changes now. After you install the Tuist app on your Mac, opening the link in the browser will automatically run the shared app in the simulator that you selected in the menu bar app.</p>
<p>
To select a simulator, choose one from the list in the menu bar app. You can also pin your favorite simulators, copy their names and identifiers, and launch them.</p>
<p>
Check out the video below to see the new app in action:</p>
<iframe title="Tuist macOS app: Streamline runinng Tuist Previews" width="560" height="315" src="https://videos.tuist.io/videos/embed/09ef419a-7398-4fed-b848-0234ae0b8738" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="future-preview-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Future Preview Improvements<a href="#future-preview-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Future Preview Improvements"></a></h2>
<p>
Wondering what else is coming to Tuist Previews? Here are some of the features we&#39;re working on:</p>
<ul>
  <li>
<strong>Run builds on your device, not just simulators:</strong> We are laying the groundwork to enable this functionality while simplifying the signing process for you. We want to ensure that signing complexities don’t detract from your experience, and we have the solution to make it seamless.  </li>
  <li>
<strong>Download the latest builds of apps from your organization:</strong> Want to try out the latest version of an app? You’ll soon be able to do so directly through the app. Imagine having a badge in your repository’s <code class="inline">README.md</code> that opens the app with just a click — mind-blowing, right? We’ll support that too.  </li>
  <li>
<strong>Android previews:</strong> We are exploring our path into the Android ecosystem and figuring out how we can provide value there. Android Previews might be one of the first steps in this direction.  </li>
</ul>
<p>
Do you have any suggestions or want to get involved? Let us know on our <a href="https://github.com/tuist/tuist/discussions">GitHub</a> or join the <a href="https://slack.tuist.io/">Slack community</a>. The app is completely open source, and you can find it <a href="https://github.com/tuist/tuist/tree/main/app">here</a>.</p>
<h2 id="the-future-of-the-macos-app" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Future of the macOS App<a href="#the-future-of-the-macos-app" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Future of the macOS App"></a></h2>
<p>
Although the macOS app is currently focused on previews, we don’t plan to stop there. We’ll continually seek out opportunities to enhance Tuist by leveraging the native capabilities of the platform, aiming to make your development experience even more enjoyable. We are committed to developing a flexible and <a href="https://tuist.dev/api/docs">well-documented</a> API, enabling any contributor to extend the app’s capabilities and even build their own clients using Apple’s robust technologies.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Swift Macros at scale ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Swift Macros, while powerful, can hinder build times. This blog post explains why and what we can do to mitigate the issue. ]]></summary>
      <link href="https://tuist.dev/blog/2024/08/26/swift-macros"/>
      <id>https://tuist.dev/blog/2024/08/26/swift-macros</id>
      <updated>Mon, 26 Aug 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/">Swift Macros</a> were introduced in September 2023 alongside Xcode 15 and have become a powerful tool for developers to leverage the compiler to generate code. The community quickly adopted them and started building and <a href="https://github.com/krzysztofzablocki/Swift-Macros">sharing them</a> as Swift Packages that teams could integrate into their projects. At Tuist, we started using <a href="https://github.com/Kolos65/Mockable">Mockable</a> as a tool to generate mocks from protocols, which we had previously been doing manually.</p>
<p>
However, Swift Macros quickly revealed a serious challenge: they can significantly increase build times, causing slow feedback cycles both locally and in CI environments. This blog post aims to explain where the build time slowness comes from, what potential solutions we might see Apple adopting, and what we can do in the meantime to mitigate the issue.</p>
<h2 id="what-is-a-swift-macro?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is a Swift Macro?<a href="#what-is-a-swift-macro?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is a Swift Macro?"></a></h2>
<p>
A Swift Macro is an executable that receives and outputs an abstract syntax tree (AST) via standard input and output. This process is called Macro Expansion. When a Swift Macro is added to an Xcode project, Xcode builds the Swift Macro into a static binary and then invokes it when the compiler encounters a piece of code that references a macro. Swift Macros typically depend on <a href="https://github.com/swiftlang/swift-syntax">SwiftSyntax</a>, a package for working with AST representations of Swift code. The compiler needs to compile SwiftSyntax along with its more than ten transitive dependencies and then link them statically against the binary to ensure the executable runs instantly.</p>
<p>
To back this blog post with data, we created a Swift Macro and used the <a href="https://github.com/sharkdp/hyperfine">hyperfine</a> tool to measure the time it takes to create a clean release build of a recently-created Swift Macro:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mkdir BenchmarkMacro &amp;&amp; cd BenchmarkMacro
swift package init --type macro
hyperfine --warmup 3 --runs 5 &#39;rm -rf .build &amp;&amp; swift build -c release&#39;    </shiki-highlight>
  </div>
</div>
<p>
The above test on a MacBook Air M2 from 2022 with 16GB of RAM yielded the following results:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
Time (mean ± σ):     196.288 s ± 23.299 s    [User: 286.626 s, System: 12.698 s]
Range (min … max):   178.014 s … 235.620 s    5 runs    </shiki-highlight>
  </div>
</div>
<p>
~3 minutes seems reasonable, but the times get worse when you add more Swift Macros to your project.</p>
<h2 id="a-non-api-stable-swiftsyntax" tabindex="-1" class="marketing__blog_post__body__content__heading">
A non-API-stable SwiftSyntax<a href="#a-non-api-stable-swiftsyntax" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A non-API-stable SwiftSyntax"></a></h2>
<p>
If you add multiple macros that depend on multiple SwiftSyntax versions, Swift Package Manager will fail to resolve the dependencies due to conflicting versions. As <a href="https://www.pointfree.co/blog/posts/116-being-a-good-citizen-in-the-land-of-swiftsyntax#be-as-flexible-as-possible-in-your-dependence-on-swiftsyntax">PointFree</a> recommends, authors should be as flexible as possible in their dependence on SwiftSyntax.</p>
<p>
Softening the version requirements of SwiftSyntax in the Swift Macros might help, but it requires SwiftSyntax to be API-stable, which will hopefully happen according to <a href="https://forums.swift.org/t/macro-adoption-concerns-around-swiftsyntax/66588/15">this comment</a> after the Swift 5.9-aligned release. Even with that in place, you&#39;d still have to rely on Apple doing a good job of making the API stable—which I think is a fair assumption—and on developers adjusting their Swift Macros to soften the version requirements.</p>
<h2 id="what-if-we-pre-compile-swiftsyntax?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What if we pre-compile SwiftSyntax?<a href="#what-if-we-pre-compile-swiftsyntax?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What if we pre-compile SwiftSyntax?"></a></h2>
<p>
Even with the above, you wouldn&#39;t get rid of the X minutes it takes to compile SwiftSyntax. One might think that Apple could provide a pre-compiled version of SwiftSyntax, but as of today, there are two large obstacles:</p>
<ul>
  <li>
SwiftSyntax is not ABI stable, so they would have to solve that first.  </li>
  <li>
Swift is not ABI stable on non-Darwin platforms (e.g., Windows, Linux).  </li>
</ul>
<p>
What this means is that even if Apple made SwiftSyntax ABI stable, providing binaries of the package wouldn&#39;t work in non-Darwin environments. Will Apple invest in that effort? That&#39;s a big question that only Apple can answer, but past work on non-Darwin platforms was traditionally done by the community.</p>
<h2 id="webassembly-to-the-rescue" tabindex="-1" class="marketing__blog_post__body__content__heading">
WebAssembly to the rescue<a href="#webassembly-to-the-rescue" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to WebAssembly to the rescue"></a></h2>
<p>
There&#39;s a technology that ticks all the boxes for what a Swift Macro needs:</p>
<ul>
  <li>
A way to run safely in a runtime.  </li>
  <li>
A way to ship a compiled version of it that runs in any version of the runtime.  </li>
</ul>
<p>
That technology is <a href="https://webassembly.org">WebAssembly</a>, and <a href="https://github.com/kabiroberai">Kabir Oberai</a> had the brilliant idea to support that as the technology to run Swift Macros. And thanks to the <a href="https://github.com/swiftwasm/WasmKit">WasmKit</a> runtime, the problem is not only solved for the Darwin platform but also for Windows and Linux. There&#39;s an <a href="https://forums.swift.org/t/poc-improving-macro-build-times-with-webassembly/70967/32">ongoing conversation</a> in the Swift Community forum, so hopefully, we&#39;ll see this technology being adopted soon, which will require Swift Macro authors to compile their Swift Macros to .wasm binaries and ship them alongside the source code.</p>
<h2 id="what-tuist-is-doing" tabindex="-1" class="marketing__blog_post__body__content__heading">
What Tuist is doing<a href="#what-tuist-is-doing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What Tuist is doing"></a></h2>
<p>
Tuist is uniquely positioned to solve this problem thanks to our ability to optimize a source&#39;s dependency graph with binaries generated from previous builds. As soon as Swift Macros came out and we started seeing the build time issues, we extended <a href="https://docs.tuist.io/guides/develop/build/cache">caching</a> to support Swift Macros too. Adopting this is very straightforward if you are using <a href="https://docs.tuist.io/guides/develop/projects">Tuist Projects</a>. All you need to do is run the following command to fingerprint and store your Swift Macros, frameworks, and bundles:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
tuist cache    </shiki-highlight>
  </div>
</div>
<p>
And the next time you or anyone on your team generates an Xcode project, they&#39;ll be using a previously-generated binary. It feels truly magical to see how fast the build times are after adopting this feature.</p>
<p>
If you want to see this in action, you can play with one of the Tuist project&#39;s fixtures:</p>
<ol>
  <li>
Clone the repository: <code class="inline">git clone https://github.com/tuist/tuist</code>.  </li>
  <li>
Install the repository dependencies: <code class="inline">mise install</code>.  </li>
  <li>
Choose the example directory: <code class="inline">cd examples/xcode/generated_framework_with_native_swift_macro</code>  </li>
  <li>
Install the project dependencies: <code class="inline">tuist install</code>  </li>
  <li>
Cache the dependencies: <code class="inline">tuist cache</code>  </li>
  <li>
Generate the Xcode project: <code class="inline">tuist generate</code>  </li>
</ol>
<p>
The following image shows the generated Xcode project where all the dependencies, including the Swift Macros, have been cached:</p>
<p>
  <img src="/marketing/images/blog/2024/08/26/swift-macros/cached-swift-macro.png" alt="Tuist Xcode project with cached Swift Macros">
</p>
<h2 id="closing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing<a href="#closing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing"></a></h2>
<p>
There are three possible solutions we might see Apple adopting:</p>
<ol>
  <li>
Making SwiftSyntax ABI and API stable, and Swift ABI stable on non-Darwin platforms.  </li>
  <li>
Using WebAssembly to run Swift Macros.  </li>
  <li>
Supporting fingerprint-based binary caching in Xcode and Swift Package Manager.  </li>
</ol>
<p>
(1) would be highly beneficial for the community, but it will test Apple&#39;s willingness to invest in other platforms or leverage the community to make that happen. (2) would show Apple&#39;s willingness to embrace web technologies, avoid reinventing the wheel, and help advance the web ecosystem, but Apple hasn&#39;t had a good record of doing that in the past. (3) would be the most pragmatic solution, but it would require Apple to make a significant investment in the build system, which has been historically slow to evolve, and there are many projects out there that accidentally build through implicit configuration that might break if such a feature is introduced.</p>
<p>
Regardless of what happens, Tuist will continue to address these challenges in the simplest and most fun way. If you are interested in learning more about Tuist, you can check out <a href="https://docs.tuist.io/">our documentation</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Introducing Tuist Previews. A URL-centric approach to collaboration ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist Previews make it easy to share apps with anyone. Learn more about this new feature and what's coming next. ]]></summary>
      <link href="https://tuist.dev/blog/2024/08/06/url-centric-collaboration"/>
      <id>https://tuist.dev/blog/2024/08/06/url-centric-collaboration</id>
      <updated>Tue, 06 Aug 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist&#39;s mission is to empower developers and organizations to build better apps faster. We&#39;ve made significant strides in supporting developers on their journey, from simplifying Xcode&#39;s complexities to optimizing build times. However, there&#39;s one area where we&#39;ve fallen short: collaboration.</p>
<p>
When a developer has something built and running and wants to share it with their team, for instance, to gather feedback, they have to jump through hoops to get it in front of the right people. Isn&#39;t it crazy that something that&#39;s right there in your environment can&#39;t be easily shared with others?</p>
<p>
Fortunately, that&#39;s no longer the case. We just released a new version of Tuist, <a href="https://github.com/tuist/tuist/releases/tag/4.23.0">4.23.0</a>, which introduces a new feature called <strong>Previews</strong>.</p>
<h2 id="the-current-state-of-collaboration" tabindex="-1" class="marketing__blog_post__body__content__heading">
The current state of collaboration<a href="#the-current-state-of-collaboration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The current state of collaboration"></a></h2>
<p>
Traditionally, teams have relied on platforms like Visual Studio <a href="https://appcenter.ms/">App Center</a>—which Microsoft has scheduled for retirement—and Apple&#39;s <a href="https://developer.apple.com/testflight/">TestFlight</a>. While TestFlight is excellent for sharing apps with testers, it&#39;s less effective for broader team sharing. To build, sign, and distribute apps, teams must set up and maintain scripts and continuous integration pipelines, which is both time-consuming and costly.</p>
<p>
Additionally, the recipient must have an Apple account (which is a reasonable assumption), be invited to a group, and only then will they receive the builds to test. These builds might have a versioning system detached from the codebase context, making it difficult to correlate feedback with the code that generated the build. For instance, encountering a bug in TestFlight build number 455 prompts questions like: Was this build generated from a commit in main? From a PR? Or was it built and pushed by a teammate from their local environment? This uncertainty is problematic.</p>
<p>
We believe collaboration needs a much simpler, web-centric approach:</p>
<ul>
  <li>
Sharing a build should be as easy as sending a link.  </li>
  <li>
It should be possible to share something running right in the simulator.  </li>
  <li>
Builds should include associated context to facilitate forwarding feedback to the appropriate person.  </li>
  <li>
Complexities like signing should not be a hindrance.  </li>
</ul>
<p>
These principles are embodied in Tuist Previews, which we believe will herald a new era of collaboration for development teams.</p>
<h2 id="tuist-previews" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist Previews<a href="#tuist-previews" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist Previews"></a></h2>
<p>
Tuist Previews make it easy to share apps with anyone. Once the app is built, you can effortlessly turn it into a link with a single command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist share MyApp    </shiki-highlight>
  </div>
</div>
<p>
The command will output a link that anyone can use to run the app with another simple command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist run https://tuist.io....    </shiki-highlight>
  </div>
</div>
<iframe title="Tuist Previews: Simplifying app sharing and collaboration" src="https://videos.tuist.io/videos/embed/46f2cfb5-7f7b-43fd-8350-87dda8476dc7" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms">
</iframe>
<h2 id="xcode-projects-support" tabindex="-1" class="marketing__blog_post__body__content__heading">
Xcode projects support<a href="#xcode-projects-support" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Xcode projects support"></a></h2>
<p>
We are gradually weakening the dependency with Tuist projects. Features like Previews and upcoming features will work directly with your Xcode projects. This means that you can use Tuist to build and run your apps, even if you don&#39;t use Tuist to generate your projects.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
This is just the beginning of Tuist Previews. We are eager to hear your feedback and prioritize it alongside some of the following features we have in mind:</p>
<ul>
  <li>
<strong>Device support:</strong> Previews currently work only on simulators, but we plan to add support for physical devices. We are developing open-source technologies and infrastructure to abstract away the intricacies of reliably signing apps. Our goal is to prevent any complexity from affecting the developer experience.  </li>
  <li>
<strong>macOS app:</strong> Non-developers may not feel comfortable running a command-line tool to use an app. We are building a macOS app that will make it easier to run and share apps. This app will serve as the foundation for more features that need to integrate natively with the macOS platform.  </li>
  <li>
<strong>Feedback:</strong> We aim to include metadata in previews and give developers the option to integrate an SDK that will allow users to report feedback. We&#39;ll handle forwarding that feedback to the appropriate team member.  </li>
  <li>
<strong>Releases:</strong> When you want to share the app with Apple, that&#39;s a release! We&#39;ll provide tools for this process, abstracting away any complexity, including signing, and offering remote environments so that you don&#39;t need to deal with intricate CI pipelines.  </li>
</ul>
<p>
<strong>Tuist Previews is a love letter to simplicity</strong> and continues to shape Tuist as an Omakase experience for app developers. We&#39;re excited to see how teams leverage this feature to build better apps faster. If you have any feedback or ideas, please share them with us on <a href="https://github.com/tuist/tuist">GitHub</a> or <a href="https://slack.tuist.io">Slack</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Empowering teams to build better apps faster ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist is shifting its focus to empower teams to build better apps faster. Learn more about our new vision and what's coming next. ]]></summary>
      <link href="https://tuist.dev/blog/2024/07/16/empower-teams-to-build-better-apps-faster"/>
      <id>https://tuist.dev/blog/2024/07/16/empower-teams-to-build-better-apps-faster</id>
      <updated>Tue, 16 Jul 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist started in 2017 with a very narrow focus.
<strong>Making Xcode&#39;s complexities more manageable.</strong>
Since then,
we&#39;ve grown to be an indispensable tool for many development teams to build their apps:</p>
<ul>
  <li>
<a href="https://asana.com/inside-asana/scaling-a-mature-ios-codebase-with-tuist">Asana scaled their iOS codebase with Tuist</a>  </li>
  <li>
<a href="https://medium.com/bumble-tech/scaling-ios-at-bumble-76754fa874f7">Bumble chose it over Bazel and SPM to scale their development</a>  </li>
  <li>
<a href="https://medium.com/trendyol-tech/revamping-trendyols-ios-app-a-modularization-success-story-a6c1d2c4188b">Trendyol made Tuist their modularization cornerstone</a>  </li>
</ul>
<p>
During this journey, we&#39;ve learned a lot about the challenges teams face when building apps.
And we built solutions for those challenges,
like slow build or test times,
stretching Tuist&#39;s original focus around Xcode&#39;s complexities.
This left organizations and developers confused about what Tuist is and what it does.
Therefore, we decided to revisit our mission and vision and share it with all of you.</p>
<h2 id="from-idea-to-top-notch-apps" tabindex="-1" class="marketing__blog_post__body__content__heading">
From idea to top-notch apps<a href="#from-idea-to-top-notch-apps" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to From idea to top-notch apps"></a></h2>
<p>
Apps usually start with an idea or a business need. Ideas can fade away if they&#39;re not validated quickly, and potentially great apps may never see the light of day. Unfortunately, the Apple platform has grown in complexity over the years, creating challenges and friction that developers and organizations need to navigate. Luckily, the community has built excellent open-source tools to assist developers with various challenges they face. However, developers still have to do the job of gluing these tools together into workflows that are a joy to use, sometimes in programming languages they are not familiar with, and maintain them indefinitely.</p>
<p>
We believe there must be a better way: an <a href="https://en.wikipedia.org/wiki/Omakase">&quot;omakase&quot;</a> for app developers. We envision an integrated experience with sensible defaults and the right extensibility points. This experience would hold your hand from the moment you start your project until you ship it to your users, helping you scale your development and your team. It would be an experience that can be easily ported from one project to another, from one team to another, and from one organization to another. We are building that experience with Tuist.</p>
<p>
<strong>We are shifting our focus to empower teams to build better apps faster.</strong></p>
<h2 id="meeting-developers-where-they-are" tabindex="-1" class="marketing__blog_post__body__content__heading">
Meeting developers where they are<a href="#meeting-developers-where-they-are" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Meeting developers where they are"></a></h2>
<p>
Our strategy has always been to meet developers where they are by integrating with the official tools and APIs provided by Apple and equipping them with superpowers. A good testament to this work is our caching feature, which leverages Xcode primitives to achieve this. We will continue with this approach, minimizing abstractions as much as possible, aligning with Apple&#39;s direction, and embracing the languages and tools that developers are familiar with and love, such as <a href="https://www.swift.org/">Swift</a>.</p>
<p>
Moreover, we are taking the approach of meeting developers where they are even further. We believe that ignoring the fact that developers spend significant time on platforms like <a href="https://slack.com">Slack</a>, <a href="https://github.com">GitHub</a>, and <a href="https://gitlab.com">GitLab</a> is a mistake. Developers often spend a substantial portion of their time there collaborating with each other and with other teams and roles. It is crucial that their workflows integrate seamlessly with these platforms, so that anyone in the organization can access the information they need to make informed decisions without having to install developer-specific toolchains. Therefore, we are embracing the web platform and URLs as units of collaboration. Developers and organizations that want to extend Tuist&#39;s capabilities further will be able to do so by plugging their projects into a server, and voila.</p>
<p>
<strong>Tuist becomes a unified toolchain that encompasses both the client (CLI) and the server (formerly Tuist Cloud).</strong></p>
<h2 id="the-lifecycle-of-an-app" tabindex="-1" class="marketing__blog_post__body__content__heading">
The lifecycle of an app<a href="#the-lifecycle-of-an-app" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The lifecycle of an app"></a></h2>
<p>
The toolchain will reflect the lifecycle of apps, from their creation to their release. The CLI, the dashboard, and our documentation will all mirror this lifecycle. We believe it’s crucial for developers to feel comfortable understanding and using the toolchain. Long-term, we aim for Tuist’s interface, which is very client-centric today, to evolve as follows:</p>
<ul>
  <li>
<strong>tuist init:</strong> Create a new project from community or Tuist-provided templates.  </li>
  <li>
<strong>tuist build:</strong> Build my project reliably and quickly, collecting insights.  </li>
  <li>
<strong>tuist test:</strong> Test my project reliably and quickly, collecting insights such as test coverage, performance, and flakiness.  </li>
  <li>
<strong>tuist lint:</strong> Validate the project or the artifacts generated from builds.  </li>
  <li>
<strong>tuist share:</strong> Share this app with my team or external people for feedback.  </li>
  <li>
<strong>tuist workflow:</strong> Run a Swift-based workflow locally, or manage the ones running remotely.  </li>
  <li>
<strong>tuist release:</strong> Trigger a release of my app to the App Store or any other distribution channel.  </li>
</ul>
<p>
Drawing inspiration from the <a href="https://www.ruby-lang.org/en/">Ruby</a> and <a href="https://rubyonrails.org/">Ruby on Rails</a> communities, from which we have learned a lot, we will design the interface of Tuist to optimize for joy and invest in Swift extensibility to foster a vibrant ecosystem of plugins and integrations. More on this in the coming months.</p>
<h2 id="embracing-openness" tabindex="-1" class="marketing__blog_post__body__content__heading">
Embracing openness<a href="#embracing-openness" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Embracing openness"></a></h2>
<p>
The best organizations that we aspire to be like have one thing in common: <em>openness</em> (e.g., <a href="https://supabase.com/">Supabase</a>, <a href="https://gitlab.com">GitLab</a>, <a href="https://posthog.com">PostHog</a>). Being open is what has brought us to where we are. It’s how we built trust with our users, created a foundation for diverse ideas, fostered collaboration, and, without a doubt, developed high-quality software that lasts and solves real problems. We are committed to doubling down on this value.</p>
<p>
We are working on establishing a path and timeline to open-source everything we do without compromising our ability to build a sustainable business. We are documenting how we are building the company in a <a href="https://handbook.tuist.io">public handbook</a> that is available for everyone to read. We believe that having <strong>a handbook will enable a frictionless and asynchronous remote work environment, attracting the best talent from around the world.</strong> As first-time founders on this journey, we also aim to inspire others to start their own companies and share their learnings with the world.</p>
<p>
We will also <strong>commoditize some pieces of technology</strong> that we’ve noticed are common across many organizations to help elevate innovation at different layers of the stack. We believe that by doing so, we can help organizations focus on what differentiates them rather than on focusing on zero-sum game. Expect a handful of open-source projects from us in the coming months.</p>
<h2 id="a-simple-and-open-pricing-model" tabindex="-1" class="marketing__blog_post__body__content__heading">
A simple and open pricing model<a href="#a-simple-and-open-pricing-model" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A simple and open pricing model"></a></h2>
<p>
The features that require a server are part of a paid plan, ensuring we can work on the project full-time and continue to support you with the challenges you face. Today, <strong>we are pleased to announce our plans publicly,</strong> focusing on simplicity and openness. We believe users shouldn’t have to figure out which plan works best for them. Everyone has access to every feature in each plan and simply pays based on usage and the level of support they desire from us.</p>
<ul>
  <li>
<strong>Tuist Air:</strong> For individual developers and small companies that don&#39;t need a dedicated support channel.  </li>
  <li>
<strong>Tuist Pro:</strong> For medium to large companies that need a dedicated support channel.  </li>
</ul>
<p>
Only enterprise models are privately discussed, as they are tailored to the needs of large organizations (e.g., custom terms, SLAs, and support).</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
We are beginning to work on the vision outlined above. To achieve this, we are developing foundational technology that we will open source in the coming months. Additionally, we are undergoing a website redesign with the amazing <a href="https://www.guindastudio.com/">Guinda</a> team to reflect the new vision and make it easier for you to understand what Tuist is and how it can help you.</p>
<p>
We will also double down on investing in our community to provide the Apple ecosystem with the best toolchain for building better apps faster.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist now supports detecting flaky tests ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist now supports detecting flaky tests. Learn how it works and how it can help you ship more reliable software ]]></summary>
      <link href="https://tuist.dev/blog/2024/07/10/detecting-flaky-tests"/>
      <id>https://tuist.dev/blog/2024/07/10/detecting-flaky-tests</id>
      <updated>Wed, 10 Jul 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When developing software, it&#39;s standard practice to write tests to ensure that code behaves as expected. In the Apple ecosystem, developers have been using <a href="https://developer.apple.com/documentation/xctest">XCTest</a> to write tests for their Swift and Objective-C codebases. Recently, <a href="https://developer.apple.com/xcode/swift-testing/">Swift Testing</a> was introduced, addressing many of XCTest&#39;s shortcomings and advancing the state of the art in testing Swift code.</p>
<h2 id="understanding-flaky-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
Understanding Flaky Tests<a href="#understanding-flaky-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Understanding Flaky Tests"></a></h2>
<p>
If you&#39;ve written tests before, you might know that tests might yield inconsistent results across runs. These are often referred to as <a href="https://docs.gitlab.com/ee/development/testing_guide/unhealthy_tests.html#flaky-tests">&quot;flaky tests&quot;</a>. In other words, flaky tests are not deterministic. They might fail due to race conditions or dependencies on the environment in which they run.</p>
<p>
Flaky tests can be quite frustrating and time-consuming. Imagine this scenario:</p>
<ol>
  <li>
You change one line of Swift code in your project.  </li>
  <li>
You push the changes upstream.  </li>
  <li>
After waiting half an hour for results (unless you&#39;re using <a href="https://docs.tuist.io/cloud/binary-caching.html">Tuist cache</a> to reduce those times), you see that your CI pipeline has failed due to a failing test unrelated to your changes.  </li>
  <li>
Developers commonly retry the build to see if the test passes the second time.  </li>
  <li>
Meanwhile, another contribution lands, causing conflicts in your branch.  </li>
  <li>
After an entire hour, you&#39;re still trying to see if your changes pass on CI.  </li>
  <li>
Finally, after 1.5 hours, your changes are green and ready to be merged.  </li>
</ol>
<p>
<strong>That&#39;s 1.5 hours of your time for a single line of code change.</strong> This is a significant problem that many companies don&#39;t address because tools to detect flaky tests are not widely available. But we&#39;re here to change that.</p>
<h2 id="why-flakiness-is-worth-solving" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why Flakiness is Worth Solving<a href="#why-flakiness-is-worth-solving" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why Flakiness is Worth Solving"></a></h2>
<p>
<strong>Tuist&#39;s aim is to help teams build better apps faster.</strong> If a codebase contains flaky tests:</p>
<ol>
  <li>
The team wastes time.  </li>
  <li>
They might ship bugs to users because tests are not reliable.  </li>
</ol>
<p>
Flaky tests are detrimental to the team&#39;s productivity and the quality of the software they ship. Therefore, we felt it was a challenge we had to help solve.</p>
<p>
The Tuist team set out to provide a solution in <strong>three phases:</strong></p>
<ol>
  <li>
Bring awareness by detecting flakiness.  </li>
  <li>
Help teams prevent flakiness when introducing new tests.  </li>
  <li>
Provide tools to automatically or manually disable tests.  </li>
</ol>
<p>
We&#39;re thrilled to announce that <strong>the first phase is now available in Tuist for anyone to use.</strong></p>
<h2 id="detecting-flaky-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
Detecting Flaky Tests<a href="#detecting-flaky-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Detecting Flaky Tests"></a></h2>
<p>
You might wonder how we solved this issue. A test is flaky if it produces different results when run multiple times without changes. The key question is: <em>how do we know if a test has changed?</em></p>
<p>
In a standard Xcode project, this information is hard to obtain outside of Xcode&#39;s build system. An approximation could be made through static analysis of imports, but this could be inaccurate for projects using dynamic features like compile-time resolved macros or compiler directives.</p>
<p>
Fortunately, Tuist has a great foundation to build upon. Our hashing logic, used for cache and smart test runs, allows us to determine if a test has changed. <strong>We consider a test unchanged if the hash of its containing module remains the same.</strong> We persist these results over time.</p>
<p>
This happens automatically if you run your tests with <a href="https://docs.tuist.io/guide/automation/test.html"><code class="inline">tuist test</code></a>. We recommend adopting this over other abstractions, as it provides access to smart test runs and analytics to understand your projects and make informed decisions.
With this information, Tuist can provide a list of tests detected as flaky. In this iteration, we just provide the list of tests for which we&#39;ve noticed inconsistencies. In the future, we plan to include a score indicating how flaky a test is, based on its run history.</p>
<p>
  <img src="/marketing/images/blog/2024/07/10/detecting-flaky-tests/flaky-test.png" alt="An image that shows the dahboard with a list of tests, some of which have been marked as flaky">
</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
This is just the beginning of our work in this area. We&#39;ll iterate with teams to ensure the detection feature works well with XCTest and Swift Testing. We&#39;ll also refine the user interface to present actionable information. After that, we&#39;ll focus on preventing flakiness, which will be seamlessly integrated into the tuist test workflow. Finally, we&#39;ll provide tools to disable flaky tests, such as rules for automatic disabling or a command for manual disabling.</p>
<p>
We believe this is a crucial feature for any team that wants to ship reliable software. If you want to try it <a href="https://docs.tuist.dev/en/server/introduction/accounts-and-projects">create an account</a> and run <code class="inline">tuist test</code> in your project. We welcome your feedback and look forward to hearing from you.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Announcing our Tuist open source program ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We are thrilled to announce that we are offering Tuist completely free for open source projects. ]]></summary>
      <link href="https://tuist.dev/blog/2024/04/25/tuist-cloud-free-for-open-source"/>
      <id>https://tuist.dev/blog/2024/04/25/tuist-cloud-free-for-open-source</id>
      <updated>Thu, 25 Apr 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist is our comprehensive platform designed to build Xcode apps quickly and <strong>scale them to millions of users.</strong> Organizations can achieve <a href="https://swiftheroes.com/swiftheroes-2024/talk/QN3WRR/">build time improvements of 70%</a> and more, and we are actively developing additional tools to assist organizations and platform teams in scaling up development (more details coming soon).</p>
<p>
As a commercial open source company with open source at its core, we understand how challenging it can be to find support for your project to ensure its sustainability and continued contribution to society with common goods that benefit everyone. Therefore, <strong>we are thrilled to announce that we are offering Tuist our paid features completely free for open source projects.</strong></p>
<p>
Please note that Tuist <a href="https://docs.tuist.io/guide/introduction/adopting-tuist/swift-package.html">has basic support for Swift Packages</a>, allowing you to test Tuist against your existing Swift Packages to better understand the workflows and how features like binary caching can enhance your projects. It’s truly magical to experience! If your project still uses Xcode primitives such as <code class="inline">.xcodeproj</code> or <code class="inline">.xcworkspace</code>, or <a href="https://docs.tuist.io/guide/introduction/adopting-tuist/migrate-from-xcodegen.html">another generation tool</a>, we have put together some migration guidelines to facilitate the process. The migration is well worth it.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/idPCBnPwHcU?si=RDlB7MPWRbGHQ6zF" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="allowfullscreen">
</iframe>
<h2 id="how-to-join-the-program" tabindex="-1" class="marketing__blog_post__body__content__heading">
How to join the program<a href="#how-to-join-the-program" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How to join the program"></a></h2>
<p>
The only requirement is to include a note in the <code class="inline">README.md</code> of the repository and send us a link to the repository along with your account handle at contact@tuist.dev. We’ll set your plan and you are good to go.</p>
<h2 id="what’s-coming-to-tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s coming to Tuist<a href="#what’s-coming-to-tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s coming to Tuist"></a></h2>
<p>
Build and test optimizations are just the beginning for Tuist. There are other challenges and areas that traditionally require organizations to invest significant time and resources, often absorbing substantial complexity themselves. We aim to alleviate this burden by providing support early in the app development lifecycle, before Xcode projects become unmanageable and unproductive. We have many ideas for future enhancements, but we’ll save those for a future blog post.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Revamping our documentation ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post, we share the journey we've been through to revamp the Tuist documentation and what we've learned. ]]></summary>
      <link href="https://tuist.dev/blog/2024/04/09/documentation-revamp"/>
      <id>https://tuist.dev/blog/2024/04/09/documentation-revamp</id>
      <updated>Tue, 09 Apr 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
One of the amazing things about open source is that anyone can contribute to a project and that means new and diverse perspectives can be brought to the table. However, that poses a challenge for maintainers: <strong>how do you ensure that the project remains coherent and consistent when contributions come from so many different sources?</strong> This challenge is not unique to code contributions, but also to documentation contributions. And this, unfortunately, is a challenge that we didn&#39;t handle well in the past. The result was a documentation that was inconsistent, outdated, and hard to navigate. But not anymore, since we&#39;ve been working on revamping our documentation and we finally made it public at <a href="https://docs.tuist.io">docs.tuist.io</a>. In this update we&#39;ll share a bit about the journey we&#39;ve been through and what we&#39;ve learned.</p>
<h2>
Documentation V1 - <a href="https://docusaurus.io/">Docusaurus</a></h2>
<p>
The first version of Tuist documentation was powered by <a href="https://docusaurus.io/">Docusaurus</a>, a NodeJS tool for generating static documentation satisfies. The framework provided us with all the tools necessary for creating a good documentation: a search engine, a sidebar, and a clean layout.</p>
<p>
Moreover, we were quite strict about the <strong>importance of updating the documentation as part of making contributions</strong>. In other words, &quot;I&#39;ll do it in a different&quot; PR was not an option. This was a good practice that helped us keep the documentation up-to-date. However, that strictness faded away as the project grew and the number of contributors increased. The result was a documentation that was outdated and hard to navigate.</p>
<p>
Because the tool required to set up the right version of <a href="https://nodejs.org">NodeJS</a> in the environment, and have a bit of knowledge about the underlying technology <em>(e.g. installing dependencies with <code class="inline">npm</code> or running commands through <code class="inline">npm run</code>)</em> we started to ponder whether that&#39;d feel as unnecessary friction for contributors. Around the same time that we were thinking about the contributors&#39; friction, Apple released <a href="https://www.swift.org/documentation/docc/">Swift DocC</a>, a tool for generating documentation for Swift projects. We thought that it&#39;d be a good opportunity to revamp the documentation and make it more accessible to contributors.</p>
<h2>
Documentation V2 - <a href="https://www.swift.org/documentation/docc/">Swift DocC</a></h2>
<p>
As part of the effort to release <a href="/blog/2024/02/07/unveiling-tuist-4-and-tuist-cloud">Tuist 4</a> we thought it&#39;d be a good opportunity to revamp the documentation and make it more accessible to contributors. We decided to use <a href="https://www.swift.org/documentation/docc/">Swift DocC</a> for generating the documentation. Many aspects of it read well in paper:</p>
<ul>
  <li>
It&#39;s writen in Swift  </li>
  <li>
It&#39;s tightly integrated into Xcode  </li>
  <li>
It can generate documentation from in-code documentation  </li>
  <li>
It&#39;s open source  </li>
  <li>
It has the notion of tutorials  </li>
</ul>
<p>
However, the more we used it, the more we realized that it was not a good fit for our needs. In hindsight, we should have done a better research before making the decision, but we trusted the tool because it was developed by Apple. Here are some aspects that turned out to be not good for us:</p>
<ul>
  <li>
<strong>The tool generates an actual SPA</strong> using <a href="https://vuejs.org/">Vue</a>. Even though search engines are supposedly able to index SPAs, the indexing of Google degraded significantly having pages that were not indexed at all. Apple seems to be aware of the issue and they have plans to work on but it seems to be a low priority.  </li>
  <li>
<strong>It has no support for i18n</strong>. We want to set up a localization pipeline for our documentation site to ensure that languages are never a barrier for users and contributors. Sadly, Swift DocC doesn&#39;t have support for that. Not only that, but uses very proprietary formats that might complicate the integration with translation tools that expect more standard formats like <a href="https://en.wikipedia.org/wiki/Markdown">Markdown</a>.  </li>
  <li>
<strong>Little extensibility and configurability:</strong> Which means that you can&#39;t do things like generating content dynamically, customizing the <code class="inline">&lt;head/&gt;</code> section of the generated pages, customizing the routes, or changing the favicon. As a consequence, we had to have some scripts that worked directly with the output artifacts.  </li>
</ul>
<p>
So while we were able to generate a documentation site that had the look-and-feel of Apple. We ended up with a tool that would limit us in the future. Moreover, we learned that the hesitance of contributors to update the documentation was not due to the tooling but rather to the lack of a culture of updating the documentation. In fact, with the introduction of Mise as a tool to manage the project&#39;s system dependencies, installing NodeJS and running <code class="inline">npm install</code> was not a big deal anymore.</p>
<p>
Moreover, with the rush to release Tuist 4, we didn&#39;t have the time to properly organize the documentation and the content, so we end up in a terrible spot with content that was outdated, pages that were missing content, and a navigation that was hard to follow.</p>
<p>
We decided to go back to the drawing board and think about what we wanted from the documentation.</p>
<h2>
Documentation V3 - <a href="https://vitepress.dev/">VitePress</a></h2>
<p>
We had been following the amazing work the <a href="https://vuejs.org/">Vue</a> ecosystem does with their tools. One of theme, <a href="https://vitepress.dev/">VitePress</a>, is a tool that they use to generate the documentation website for all their projects. It&#39;s aesthetically pleasing, it&#39;s extensible and configurable, it outputs a SSG site, it supports i18n, and it&#39;s actively maintained. It had everything we needed.</p>
<p>
Like many times in the pass, we were confronted with the decision between choosing the right tool for the job, even if that meant choosing a technology stack other than Swift and Xcode, or sticking with the existing &quot;official&quot; options and trying to make them work. However, since we are limited in resources and getting involved in a project that&#39;s mainly steered by Apple would be a big commitment that would distract us from our main goal, we decided to go with VitePress.</p>
<p>
It took us almost an entire week to go through all the versions of the documentation website pulling content from the old documentation, updating it, and organizing it. We also took the opportunity to add new content and improve the existing one. We also organized the content in the following sections for ease of navigation: Guides, Reference, Contributors, and Server.
The result of the work is already available under <a href="https://docs.tuist.io">docs.tuist.io</a>.</p>
<p>
We have to admit that the experience working with VitePress has been top-notch. As an example of how powerful is extensibility is, we could use a tool like <a href="https://github.com/SourceDocs/SourceDocs">SourceDocs</a> to turn in-code documentation into Markdown pages and dynamically load the content using VitePress built-in APIs for <a href="https://vitepress.dev/guide/data-loading">data-loading</a>.</p>
<h2 id="preventing-the-same-mistake" tabindex="-1" class="marketing__blog_post__body__content__heading">
Preventing the same mistake<a href="#preventing-the-same-mistake" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Preventing the same mistake"></a></h2>
<p>
We made the mistake of being less strict about updating the documentation as part of making contributions. We learned that the tooling was not the problem, but rather the culture. Since we were limited in resources, it was a huge stretch for us to supervise documentation contributions on top of code contributions, our natural reaction was to ignored what it&#39;s indeed one of the most important parts of the project. We learned that we should have invested more time in creating a culture of updating the documentation as part of making contributions.</p>
<p>
Going forward, <strong>we&#39;ll require every PR to have documentation updates.</strong> Since we have the priviledge of having people working full time on the project, we&#39;ll be able to supervise the contributions and ensure that the documentation is updated. We&#39;ll also be more strict about the quality of the documentation. We&#39;ll require that the documentation is clear, concise, and easy to follow. We might consider introducing some automation to ensure certain style guidelines are followed.</p>
<h2 id="feedback" tabindex="-1" class="marketing__blog_post__body__content__heading">
Feedback<a href="#feedback" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Feedback"></a></h2>
<p>
Give it a read and <a href="https://github.com/tuist/tuist/discussions/6160">let us know what you think</a>. We&#39;re always looking for ways to improve the documentation and make it more accessible to users and contributors. On behalf of the Tuist, we&#39;d like to apologies for having disregarded the documentation for so long. We hope that the new documentation is a step in the right direction and that it helps you get started with Tuist.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 4.1.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist 4.1.0 is out with new features, improvements, and bug fixes. In this blog post, we'll cover the highlights of this release. ]]></summary>
      <link href="https://tuist.dev/blog/2024/02/12/tuist-410"/>
      <id>https://tuist.dev/blog/2024/02/12/tuist-410</id>
      <updated>Mon, 12 Feb 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
And after the exhaustive work to release Tuist 4, we are back shipping new features and improvements. Today we just released <a href="https://github.com/tuist/tuist/releases/tag/4.1.0">Tuist 4.1.0</a>, which includes new features, improvements, and bug fixes. In this blog post, we&#39;ll cover the highlights of this release.</p>
<h3 id="better-support-for-objective-c-packages" tabindex="-1" class="marketing__blog_post__body__content__heading">
Better support for Objective-C packages<a href="#better-support-for-objective-c-packages" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Better support for Objective-C packages"></a></h3>
<p>
One of our long-standing issues in our backlog were problems trying to integrate Swift Packages with Objective-C code in them. The Swift Package Manager, which was designed as a package manager for packages with Swift code, succumbed to the complexity of integrating Objective-C code. To make them work, the Swift Package Manager has some logic for generating module maps and passing the right build settings to the dependent targets. This is logic that Tuist didn&#39;t have, and therefore users had to manually figure out what were the right settings to pass to the dependent targets.</p>
<p>
Luckily, that&#39;s no longer needed from Tuist 4.1.0. <a href="https://github.com/fortmarek">Marek</a> did an <a href="https://github.com/tuist/tuist/pull/5887">amazing job</a> going deep into understanding Swift Package Manager&#39;s logic and porting it over to Tuist. If you were having issues with Objective-C packages, you can try again with Tuist 4.1.0. Please, note that there might be package scenarios out there (we look at you Google), that are convoluted and that might require additional work from us. If so, please, file an issue and we&#39;ll look into it.</p>
<h3 id="add-support-for-visionos-to-our-resource-synthesizing-templates" tabindex="-1" class="marketing__blog_post__body__content__heading">
Add support for visionOS to our resource synthesizing templates<a href="#add-support-for-visionos-to-our-resource-synthesizing-templates" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Add support for visionOS to our resource synthesizing templates"></a></h3>
<p>
As you might know, Tuist supports generating code interfaces to access resources and leverage the compiler&#39;s type safety. This is a feature that we call resource synthesizing. In Tuist 4.1.0, we added support for <code class="inline">visionOS</code> to our resource synthesizing templates. If you are building an app for visionOS, you can now use the resource synthesizing feature to access your resources in a type-safe way.</p>
<h3 id="how-to-update" tabindex="-1" class="marketing__blog_post__body__content__heading">
How to update<a href="#how-to-update" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How to update"></a></h3>
<p>
You can use <a href="https://mise.jdx.dev/">Mise</a> to install the latest version and pin it to your project. To do so, run the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
mise install tuist@4.1.0
mise local tuist 4.1.0    </shiki-highlight>
  </div>
</div>
<p>
Happy Xcoding!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Unveiling Tuist 4 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post, we unveil Tuist 4 and paid features offered through a server, marking an inflection point in the project's sustainability. We also discuss the long-term sustainability of the project and the new features in Tuist 4. We also talk about the new logo, our partnership with Codemagic, and our commitment to open-source. ]]></summary>
      <link href="https://tuist.dev/blog/2024/02/07/unveiling-tuist-4-and-tuist-cloud"/>
      <id>https://tuist.dev/blog/2024/02/07/unveiling-tuist-4-and-tuist-cloud</id>
      <updated>Wed, 07 Feb 2024 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
import Calculator from &quot;../../../../../components/Calculator&quot;;</p>
<p>
On <a href="https://github.com/tuist/XcodeProj/commit/d3f5fdb2783219d001173bf92074e2dc8853b9a4">April 21st, 2017</a>, we created the first commit in <a href="https://github.com/tuist/xcodeproj">XcodeProj</a>, motivated by <strong>the itch of overcoming the challenges of collaboration on a modular Xcode project</strong>. XcodeProj would later become the foundation of Tuist. We drew inspiration from the Swift Package Manager DSL, but we oriented its design towards maintaining and evolving Xcode projects, abstracting their intricacies.</p>
<p>
This work made us realize that project generation, which we perfected over time, was the perfect foundation to build an integrated solution for many of the challenges that organizations face. Many organizations found in Tuist the right balance between cost and investment. Tuist is approachable thanks to its Swift-based DSL and the Xcode concepts that developers are already familiar with. Teams can focus on building architectures that meet their needs without being held back by brittle, conflict prone Xcode project files.</p>
<p>
After almost 7 years of trying to understand the problem space, talking to a lot of companies and the challenges they face, and pouring days and nights into building the best developer tool in the space, we are thrilled to share with you something that we’ve been working on for the past months: a new major version of the project, Tuist 4, which marks an inflection point in the project&#39;s sustainability. But before we dive into the heart of this major release, we need to talk about sustainability.</p>
<h2 id="long-term-sustainability" tabindex="-1" class="marketing__blog_post__body__content__heading">
Long-term sustainability<a href="#long-term-sustainability" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Long-term sustainability"></a></h2>
<p>
Ensuring the sustainability of open source development is a critical concern, especially in the context of the Tuist project. Historically, open source software has often been perceived as a free good, similar to products used in traditional businesses as <a href="https://en.wikipedia.org/wiki/Loss_leader">loss leaders</a> to entice customers into purchasing non-free goods. However, the reality is more nuanced.</p>
<p>
<strong>Open source, with its near-zero marginal costs due to economies of scale</strong>, has the potential to create a high <a href="https://en.wikipedia.org/wiki/Economic_surplus">consumer surplus</a>. This surplus can be justified for products, particularly intellectual property, and has historically been funded through government-sponsored research and development efforts or private foundations and volunteer contributions in the open source community.</p>
<p>
However, the uniqueness of software lies in its ongoing maintenance requirements. Unlike pure intellectual property, <strong>software is a product that needs continuous updates</strong>, bug fixes, and improvements. Consequently, the traditional free good model often falls short when it comes to software. There is a pressing need to secure ongoing funding to ensure its maintenance and development.</p>
<p>
Tuist, as a project, has reached a level of popularity that necessitates substantial maintenance efforts. Relying solely on volunteer contributions or donations has proven insufficient to meet these demands. Consequently, a new approach is required to sustain Tuist effectively.</p>
<p>
To address this challenge, <strong>we are embracing a commercial open source model for Tuist</strong>, with <a href="https://docs.tuist.dev/en/server/introduction/why-a-server">a server</a> serving as the inaugural commercial complement. This model offers several key advantages:</p>
<ul>
  <li>
<strong>No Resource Starvation:</strong> Tuist&#39;s costs are covered by its selling price, eliminating the resource scarcity that can plague a zero-priced open source model. It ensures the project&#39;s financial sustainability.  </li>
  <li>
<strong>No Hidden Costs:</strong> Open source remains genuinely free under this model, with no restrictive licensing terms or unexpected financial burdens on users.  </li>
  <li>
<strong>No Predatory Pricing:</strong> While open source may be free, it doesn&#39;t enable predatory pricing practices. Competitors can freely use the codebase to offer their solutions, fostering healthy competition and preventing monopolies.  </li>
</ul>
<p>
Unlike the conventional loss-leading strategy where free and paid offerings are identical or substitutes, our approach views them as complementary components of the Tuist ecosystem. Our paid offering represents the first step in this transition, helping us secure the necessary resources to sustain Tuist&#39;s ongoing development and guarantee its long-term viability.</p>
<p>
By embracing the commercial open source model, <strong>we are striking a balance between the benefits of open source collaboration and the sustainability of the Tuist project</strong>, ensuring that it continues to thrive and serve the community effectively.</p>
<h2 id="paid-features" tabindex="-1" class="marketing__blog_post__body__content__heading">
Paid features<a href="#paid-features" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Paid features"></a></h2>
<p>
We introduced a set of paid features via a server by leveraging the project-generation foundation. Organizations can easily self-host the server or use our hosted version, leaving updates, maintenance, and support in our hands. <strong>The service is generally available</strong> and we already have organizations using it. Key features include:</p>
<h3 id="binary-caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
Binary caching<a href="#binary-caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Binary caching"></a></h3>
<p>
Clean builds, which occur locally when developers clear derived data and commonly during CI builds, might require compiling targets that haven&#39;t changed since they were last built. When builds take place within the same environment, Xcode&#39;s build system can handle this incrementally, making the process fast. However, this incrementality doesn&#39;t extend across different environments, leading to situations where organizations&#39; CI pipelines can take up to 30 minutes and more. This is far from ideal from a developer productivity perspective.</p>
<p>
The efficiency of the cache is closely tied to the modular architecture of the project. A highly modular architecture with weak dependencies among nodes can result in <strong>significant reductions in build times, potentially up to 90%.</strong> Additionally, we can cache Swift Macros and multi-platform targets as well.</p>
<p>
  <img src="/marketing/images/blog/2024/02/07/tuist-cloud-binary-cache.gif" alt="A video that shows how binary caching works in practice">
</p>
<h3 id="selective-testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Selective testing<a href="#selective-testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Selective testing"></a></h3>
<p>
At some point in the project&#39;s journey, building and testing all the targets with every CI commit becomes inefficient. <strong>The time required is directly proportional to the project&#39;s size,</strong> and while slight improvements can be made with new processor generations, as demonstrated with M processors, CI providers struggle to keep up with the pace. When organizations reach this point, some opt to create their own in-house selective testing solutions, but this entails a significant time investment that detracts from product development. Moreover, without a tool to mitigate the inherent complexity in Xcode projects, the resulting logic can become unreliable and cause frustration among developers.</p>
<p>
We offer a selective testing solution that works seamlessly across different environments. It utilizes the same hashing logic employed by binary caching to uniquely identify binaries in the cache, this time to determine whether a target has changed and, consequently, whether its tests and those of dependent targets need to run. The best part? It operates automatically, requiring no additional configuration or complexity.</p>
<p>
  <img src="/marketing/images/blog/2024/02/07/tuist-cloud-selective-testing.gif" alt="A video that shows selective testing in practice">
</p>
<h3 id="return-of-investment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Return of investment<a href="#return-of-investment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Return of investment"></a></h3>
<p>
Supporting Tuist is a cost-effective investment, as it will likely save your team more than it costs. Your contributions support Tuist&#39;s development and other vital open-source projects in need of sustainability. We&#39;re committed to fostering a sustainable open-source ecosystem where developers can earn a living from their work.
If you want to get rough estimates of the potential savings, you can use our calculator below.</p>
<section class="flex flex-col p-[0.060rem] shadow-2xl rounded-3xl bg-gradient-to-b from-indigo-500 to-cyan-500 col-span-5">
      <div class="bg-vulcan-900 px-6 sm:px-8 pt-8 pb-10 rounded-3xl h-full">
        <Calculator showTitle={false} showDescription={false} client:visible/>
    </div></section>
<h3 id="next-steps" tabindex="-1" class="marketing__blog_post__body__content__heading">
Next steps<a href="#next-steps" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Next steps"></a></h3>
<p>
We have more ideas to tackle challenges, but our initial focus is on getting organizations on board, understanding their needs, and prioritizing development accordingly. Additionally, we aim to provide actionable metrics for project and build data, helping teams ensure their projects are future-proof.</p>
<p>
If you&#39;re eager to begin using our paid features, we recommend <a href="https://docs.tuist.dev/en/server/introduction/why-a-server">reviewing our documentation</a> and ensuring that <code class="inline">tuist cache</code> runs successfully with your Xcode project. You may need to make some adjustments to eliminate implicit configurations that could potentially hinder reliable caching.</p>
<blockquote>
  <p>
At Lapse speed is our top priority, Tuist has accelerated our development feedback loop massively. We mostly try to ship to the App Store every single day, so ensuring fast iteration speeds for feature development is of utmost importance.
Our average build time for an internal QA build or for our PR workflows used to be around 30 minutes on the CI, and when we added macros to the project this increased to 53 minutes.
Since we started using Tuist&#39;s paid features with our modularised codebase (220 modules including dependencies) we’ve seen builds as quick as 8 minutes, with the average build time now being 13 minutes with macros!
This has also dramatically impacted local development, we now no longer need to rebuild all those modules we’re not working on, which has resulted in much faster iteration speeds for the whole iOS team. Head of iOS at Lapse - Alex Little  </p>
</blockquote>
<h2 id="tuist-4" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist 4<a href="#tuist-4" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist 4"></a></h2>
<p>
In addition to our paid features offered by the server, we are introducing a major new release of Tuist, Tuist 4. With this release, we are placing a strong emphasis on sustainability.</p>
<p>
We have observed that over the years, we have developed and maintained features and components of Tuist that are peripheral to the core of the project. For instance, the version manager &quot;tuistenv&quot; has seamlessly handled the installation and activation of Tuist versions. Additionally, we have implemented contributor tooling that introduced unnecessary friction and created a significant dependency between contributors and the core maintenance team. We have not critically evaluated their necessity until recently.</p>
<h3 id="mise-as-the-default-installer" tabindex="-1" class="marketing__blog_post__body__content__heading">
Mise as the default installer<a href="#mise-as-the-default-installer" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Mise as the default installer"></a></h3>
<p>
Users used to install <code class="inline">tuistenv</code> which we renamed to <code class="inline">tuist</code> during installation, to deterministically install and activate versions of Tuist across various environments. While it served its purpose well with minimal maintenance, we felt that it was somewhat disconnected from Tuist&#39;s core mission. We believed that there were other tools available that could perform the same tasks more effectively and efficiently. In particular, we explored <a href="https://mise.jdx.dev/">Mise</a>, a tool capable of installing system tools, allowing version scoping and activation on a per-project basis. The experience was outstanding, aligning perfectly with the developer experience (DX) that Tuist aims to provide. Furthermore, Mise can serve as a versatile tool to install other dependencies commonly used in the Swift ecosystem, such as <a href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a>, Ruby, <a href="https://github.com/realm/SwiftLint">Swiflint</a>, and <a href="https://github.com/nicklockwood/SwiftFormat">Swiftformat</a>. All a project needs is a <code class="inline">.mise.toml</code> file at the root, a <code class="inline">mise install</code> command, and voilà, all the necessary versions are installed and activated.</p>
<p>
Starting from Tuist 4, Mise <a href="https://github.com/tuist/tuist/pull/5556">becomes the default installer</a>, with <a href="https://brew.sh">Homebrew</a> as an alternative for teams that prefer an intermediary step using a tool already prevalent in their development environments. Alternatively, teams can pull the binaries from GitHub releases. Tuist assumes the role of an advocate, <strong>emphasizing the importance of version determinism across different environments</strong>. Development organizations can save countless hours by avoiding non-deterministic version discrepancies that can easily occur with tools like Homebrew, especially when Mise provides a more deterministic solution. We believe Mise strikes the right balance between convenience and determinism, which is why we have chosen it as our new installer.</p>
<p>
We would like to express our gratitude to <a href="https://twitter.com/jdxcode">@jdx</a>, the creator and maintainer of Mise, for the outstanding work they have done with the tool and their ongoing support to ensure Tuist and Xcode developers have the smoothest experience possible.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<p>
When Apple integrated Swift Packages into Xcode, they introduced a new post-XcodeProj-open phase in the Xcode project to resolve dependencies asynchronously. This product decision seemed consistent with <strong>Apple&#39;s approach to make their solutions as convenient as possible</strong>. However, it came at the cost of providing teams with limited flexibility over the developer experience, dependency integration, and optimizations.</p>
<p>
Shortly after its release, the downsides of this idea became evident. Package products determining their static/linking nature had cascading integration effects, which Apple addressed by introducing an &quot;automatic&quot; linking option. Delegating these responsibilities to the build system increased dependence on Apple and the underlying build system for optimization. This strong dependency wasn&#39;t desirable, especially for large-scale projects.</p>
<p>
This motivated us to take a different approach, where <strong>we aimed to provide users with more control over integration, making it compatible with Tuist for easy binary caching of dependencies.</strong> We introduced a <code class="inline">Dependencies.swift</code> file where users could define their package dependencies. A <code class="inline">tuist fetch</code> command would resolve these dependencies using the Swift Package Manager. At generation time, we would convert them into Xcode projects, integrating, validating, and optimizing them alongside the rest of the graph. Although this feature came with ongoing maintenance costs, especially with new SPM features like Swift Macros, our experiments with binary caching showed that the investment was truly worthwhile. Tuist users embraced <code class="inline">Dependencies.swift</code>. When <code class="inline">tuist generate</code> completed, they had an optimized Xcode project ready for compilation. Additionally, they could delete derived data without worrying about invalidating package resolution. Through Xcode project generation, we enhanced developers&#39; experience using the Swift Package Manager at its core.</p>
<p>
However, the use of <code class="inline">Dependencies.swift</code> distanced us from SPM&#39;s default interface, <code class="inline">Package.swift</code>, which had cascading consequences. For instance, we couldn&#39;t utilize tools like <a href="https://github.com/dependabot">Dependabot</a> for automated dependency updates. To address this, we made changes in Tuist 4. Now, your dependencies are defined in a <code class="inline">Package.swift</code> file at the root of your project. Furthermore, you can use the <code class="inline">#if TUIST</code> compiler directive to include integration settings in the same manifest file. Additionally, we renamed <code class="inline">tuist fetch</code> to <code class="inline">tuist install</code> to align it with the industry&#39;s naming convention for dependency installation.</p>
<p>
To learn more about dependencies in <code class="inline">Package.swift</code>, you can check out <a href="https://docs.tuist.io/guide/project/dependencies">our documentation</a>.</p>
<h3 id="swift-docc-documentation-website" tabindex="-1" class="marketing__blog_post__body__content__heading">
Swift DocC documentation website<a href="#swift-docc-documentation-website" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Swift DocC documentation website"></a></h3>
<p>
Tuist previously utilized <a href="https://docusaurus.io/">Docusaurus</a>, a NodeJS-based tool, to generate a static <a href="https://docs.tuist.io">documentation website</a>. While it served its purpose well, we realized that it introduced friction for contributions. This was because it required developers to have <a href="https://nodejs.org">Node.js</a> installed, a certain level of understanding of the ecosystem, and performing documentation-related tasks from a different editor or tool than what they used for contributing to Tuist or working in Xcode.</p>
<p>
Around the same time, Apple introduced <a href="https://www.swift.org/documentation/docc/">Swift DocC</a>, a tool for statically generating documentation specifically for Swift projects. It was seamlessly integrated into Xcode and the Swift Package Manager, resulting in documentation that mirrored the style and appearance of Apple&#39;s official documentation sites since they also employed the same tool. Thus, we contemplated the idea of switching to Swift DocC. This decision would offer <strong>tighter integration into our contributors&#39; workflows and align visually with other Apple tools.</strong></p>
<p>
Consequently, we made the choice to adopt Swift DocC as our documentation-generation framework and tool, embarking on a comprehensive overhaul of our documentation. During this process, we took the opportunity to eliminate outdated documentation, bring certain sections up to date, and restructure it for enhanced navigability. Additionally, we introduced new tutorials and incorporated the API documentation generated from the ProjectDescription models into the documentation. Moving forward, we are committed to ensuring that these new documentation elements seamlessly integrate with the existing content, creating a more cohesive and user-friendly documentation experience.</p>
<h3 id="projectdescription-api-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
ProjectDescription API improvements<a href="#projectdescription-api-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to ProjectDescription API improvements"></a></h3>
<p>
<code class="inline">ProjectDescription</code> is the framework that exposes all the models developers use to describe their projects, workspaces, and configurations. Despite our best efforts to maintain consistently designed and highly readable APIs, in line with Swift frameworks, inconsistencies gradually crept in over time, and readability suffered in some areas. With major versions providing the flexibility to introduce breaking changes, we seized the opportunity to reevaluate all the APIs.</p>
<p>
In particular, we made many initializers from models private and introduced static functions that are more descriptive and offer us greater flexibility for future API iterations, without the risk of introducing breaking changes. Additionally, we made the models&#39; attributes public and mutable to enhance usability when working with the models from manifest files. Moving forward, we will closely monitor API changes to avoid falling into the same inconsistencies that led us to this point.</p>
<p>
If you are in the process of migrating a project to Tuist 4, I recommend <a href="https://docs.tuist.io">reviewing our documentation</a>, which includes information on all the available models.</p>
<br>
<p>
Many more changes have been incorporated into Tuist 4, which would significantly extend the length of this blog post. If you desire a detailed list of these changes, we recommend consulting our release notes on GitHub or reviewing the comprehensive list of issues and pull requests.</p>
<h2 id="remaining-faithful-to-tuist's-open-source-model" tabindex="-1" class="marketing__blog_post__body__content__heading">
Remaining faithful to Tuist&#39;s open-source model<a href="#remaining-faithful-to-tuist's-open-source-model" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Remaining faithful to Tuist's open-source model"></a></h2>
<p>
Introducing an additional source of funding to the project might raise concerns among users – what if every new feature becomes exclusive to paying users, and we end up adopting the loss-leading models commonly seen in traditional companies? To prevent this scenario, we are committed to embracing the open-source philosophy in the way we manage the company, ensuring accountability.</p>
<p>
To fulfill this commitment, we will begin publishing a monthly report at the end of each month. In this report, we will openly share our financial status and how the funds are being utilized to sustain Tuist. We call it <strong>Monthly Sustainability Report.</strong> Key points we will address include:</p>
<ul>
  <li>
How we have addressed issues and pull requests for both, the CLI and the server.  </li>
  <li>
The number of contributions we have made to other open-source projects on which we depend.  </li>
  <li>
The number of contributions paid through our bounty program.  </li>
  <li>
The areas on which we plan to focus based on users’ feedback.  </li>
</ul>
<p>
Each report will include a discussion topic, inviting developers to join the conversation and share their thoughts, ideas, concerns, and questions. Additionally, we will continue to make decisions by consensus with the core maintainers team, which includes representatives from companies that use Tuist.</p>
<h2 id="a-brand-new-logo" tabindex="-1" class="marketing__blog_post__body__content__heading">
A brand-new logo<a href="#a-brand-new-logo" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A brand-new logo"></a></h2>
<p>
As Tuist 4 marked a significant milestone in the project&#39;s history, we took the opportunity to undergo a logo redesign to align ourselves more closely with the icons used by Apple for their developer tools. We enlisted the talented services of <a href="https://matthewskiles.com/">Matthew Skiles</a> for this task, and he crafted a beautiful logo that now represents our new online identity.</p>
<p>
In this new logo, Matthew skillfully preserved Tuist&#39;s identity through the choice of colors and the iconic shell, while also incorporating elements that give it a distinct developer tooling feel. The result is truly impressive, and we couldn&#39;t be happier with the outcome. If you&#39;re in need of a design for your app icon, we wholeheartedly recommend Matthew. It was an incredible experience collaborating with him.</p>
<img src="/logos/logo.png" width="200" height="200">
<h2 id="strengthening-our-partnership-with-codemagic" tabindex="-1" class="marketing__blog_post__body__content__heading">
Strengthening our partnership with Codemagic<a href="#strengthening-our-partnership-with-codemagic" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Strengthening our partnership with Codemagic"></a></h2>
<p>
Since the early days of Tuist, <a href="https://codemagic.io">Codemagic</a>, a CI/CD platform designed for mobile teams, has been a staunch supporter of Tuist through sponsorships and valuable resources for the community. With the release of Tuist 4 and the paid features, they are taking their support to the next level by offering us an exceptional CI/CD service and environments. As a result, we will be transitioning all our CI pipelines to run on Codemagic. We are incredibly grateful for this support.</p>
<p>
If your company is in search of an excellent CI/CD solution for your mobile projects, we wholeheartedly recommend Codemagic. They are currently offering Tuist users <strong>a discounted annual price of $2990, down from $4788</strong>. To take advantage of this offer, simply use the code <code class="inline">TUIST2024</code> when purchasing Codemagic fixed price annual plan.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
We wouldn&#39;t be here if it weren&#39;t for the ongoing support of maintainers, sponsors, and users who showed up and believed in us. So, from the depths of our hearts, we want to express our heartfelt gratitude for standing by us. Tuist wouldn&#39;t be the same without you.</p>
<p>
The first seven years were dedicated to understanding Xcode, its intricacies, and laying the foundation for project generation. This foundation enabled us to assist organizations in overcoming their challenges. This new phase is all about continuing to do what we love for as long as possible because organizations value the tool. It&#39;s going to be an amazing journey ahead!</p>
<h2 id="thank-you-❤️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Thank you ❤️<a href="#thank-you-❤️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Thank you ❤️"></a></h2>
<p>
Tuist 4 owes its existence to the contributions of fantastic and talented builders who strive to enhance the tool for everyone. To everyone on this list, and to anyone who also contributed to Tuist but whom we couldn’t capture in GitHub contributions, my heartfelt thanks. I also extend my gratitude to the core maintainers team, <a href="https://github.com/danyf90">Daniele</a>, <a href="https://github.com/waltflanagan">Mike</a>, <a href="https://github.com/fortmarek">Marek</a>, and <a href="https://github.com/kwridan">Kas</a>, as well as to everyone who was once part of the core team and contributed to steering the project. You are all amazing.</p>
<p>
<a href="https://github.com/mohitsaxenaknoldus">&lt;img alt=&quot;mohitsaxenaknoldus&quot; src=&quot;https://avatars.githubusercontent.com/u/76725454?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/sampettersson">&lt;img alt=&quot;sampettersson&quot; src=&quot;https://avatars.githubusercontent.com/u/5459507?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/saim80">&lt;img alt=&quot;saim80&quot; src=&quot;https://avatars.githubusercontent.com/u/316606?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/SergeyPetrachkov">&lt;img alt=&quot;SergeyPetrachkov&quot; src=&quot;https://avatars.githubusercontent.com/u/7995896?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/setoelkahfi">&lt;img alt=&quot;setoelkahfi&quot; src=&quot;https://avatars.githubusercontent.com/u/1797197?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/JCSooHwanCho">&lt;img alt=&quot;JCSooHwanCho&quot; src=&quot;https://avatars.githubusercontent.com/u/51935215?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/mohitsaxenaknoldus">mohitsaxenaknoldus</a> |<a href="https://github.com/sampettersson">sampettersson</a> |<a href="https://github.com/saim80">saim80</a> |<a href="https://github.com/SergeyPetrachkov">SergeyPetrachkov</a> |<a href="https://github.com/setoelkahfi">setoelkahfi</a> |<a href="https://github.com/JCSooHwanCho">JCSooHwanCho</a> |</p>
<p>
<a href="https://github.com/st-small">&lt;img alt=&quot;st-small&quot; src=&quot;https://avatars.githubusercontent.com/u/1850189?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/steprescott">&lt;img alt=&quot;steprescott&quot; src=&quot;https://avatars.githubusercontent.com/u/1131458?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/rist">&lt;img alt=&quot;rist&quot; src=&quot;https://avatars.githubusercontent.com/u/295229?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/kalkwarf">&lt;img alt=&quot;kalkwarf&quot; src=&quot;https://avatars.githubusercontent.com/u/1033839?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/stevelandeyasana">&lt;img alt=&quot;stevelandeyasana&quot; src=&quot;https://avatars.githubusercontent.com/u/38225497?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/stephanecopin">&lt;img alt=&quot;stephanecopin&quot; src=&quot;https://avatars.githubusercontent.com/u/7003579?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/st-small">st-small</a> |<a href="https://github.com/steprescott">steprescott</a> |<a href="https://github.com/rist">rist</a> |<a href="https://github.com/kalkwarf">kalkwarf</a> |<a href="https://github.com/stevelandeyasana">stevelandeyasana</a> |<a href="https://github.com/stephanecopin">stephanecopin</a> |</p>
<p>
<a href="https://github.com/sujata23">&lt;img alt=&quot;sujata23&quot; src=&quot;https://avatars.githubusercontent.com/u/1849089?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/c0diq">&lt;img alt=&quot;c0diq&quot; src=&quot;https://avatars.githubusercontent.com/u/172535?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tejassharma96">&lt;img alt=&quot;tejassharma96&quot; src=&quot;https://avatars.githubusercontent.com/u/8764853?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tosbaha">&lt;img alt=&quot;tosbaha&quot; src=&quot;https://avatars.githubusercontent.com/u/971530?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/NataliaKurek">&lt;img alt=&quot;NataliaKurek&quot; src=&quot;https://avatars.githubusercontent.com/u/19759844?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/nivanchikov">&lt;img alt=&quot;nivanchikov&quot; src=&quot;https://avatars.githubusercontent.com/u/1830010?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/sujata23">sujata23</a> |<a href="https://github.com/c0diq">c0diq</a> |<a href="https://github.com/tejassharma96">tejassharma96</a> |<a href="https://github.com/tosbaha">tosbaha</a> |<a href="https://github.com/NataliaKurek">NataliaKurek</a> |<a href="https://github.com/nivanchikov">nivanchikov</a> |</p>
<p>
<a href="https://github.com/oronbz">&lt;img alt=&quot;oronbz&quot; src=&quot;https://avatars.githubusercontent.com/u/1288090?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Austinate">&lt;img alt=&quot;Austinate&quot; src=&quot;https://avatars.githubusercontent.com/u/4790464?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/wogus3602">&lt;img alt=&quot;wogus3602&quot; src=&quot;https://avatars.githubusercontent.com/u/46857148?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/BalestraPatrick">&lt;img alt=&quot;BalestraPatrick&quot; src=&quot;https://avatars.githubusercontent.com/u/3658887?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/PaulTaykalo">&lt;img alt=&quot;PaulTaykalo&quot; src=&quot;https://avatars.githubusercontent.com/u/119268?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/pavm035">&lt;img alt=&quot;pavm035&quot; src=&quot;https://avatars.githubusercontent.com/u/6092412?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/oronbz">oronbz</a> |<a href="https://github.com/Austinate">Austinate</a> |<a href="https://github.com/wogus3602">wogus3602</a> |<a href="https://github.com/BalestraPatrick">BalestraPatrick</a> |<a href="https://github.com/PaulTaykalo">PaulTaykalo</a> |<a href="https://github.com/pavm035">pavm035</a> |</p>
<p>
<a href="https://github.com/petrukha-ivan">&lt;img alt=&quot;petrukha-ivan&quot; src=&quot;https://avatars.githubusercontent.com/u/93926277?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/platonsi">&lt;img alt=&quot;platonsi&quot; src=&quot;https://avatars.githubusercontent.com/u/46824695?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Arafo">&lt;img alt=&quot;Arafo&quot; src=&quot;https://avatars.githubusercontent.com/u/560392?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/OhKanghoon">&lt;img alt=&quot;OhKanghoon&quot; src=&quot;https://avatars.githubusercontent.com/u/18064037?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/enlivn">&lt;img alt=&quot;enlivn&quot; src=&quot;https://avatars.githubusercontent.com/u/78372052?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/rmnblm">&lt;img alt=&quot;rmnblm&quot; src=&quot;https://avatars.githubusercontent.com/u/5942764?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/petrukha-ivan">petrukha-ivan</a> |<a href="https://github.com/platonsi">platonsi</a> |<a href="https://github.com/Arafo">Arafo</a> |<a href="https://github.com/OhKanghoon">OhKanghoon</a> |<a href="https://github.com/enlivn">enlivn</a> |<a href="https://github.com/rmnblm">rmnblm</a> |</p>
<p>
<a href="https://github.com/RomanPodymov">&lt;img alt=&quot;RomanPodymov&quot; src=&quot;https://avatars.githubusercontent.com/u/10789692?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/schinj">&lt;img alt=&quot;schinj&quot; src=&quot;https://avatars.githubusercontent.com/u/7895596?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/cheskapac">&lt;img alt=&quot;cheskapac&quot; src=&quot;https://avatars.githubusercontent.com/u/2336961?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dcramps">&lt;img alt=&quot;dcramps&quot; src=&quot;https://avatars.githubusercontent.com/u/643865?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/euriasb">&lt;img alt=&quot;euriasb&quot; src=&quot;https://avatars.githubusercontent.com/u/3721257?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/fossabot">&lt;img alt=&quot;fossabot&quot; src=&quot;https://avatars.githubusercontent.com/u/29791463?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/RomanPodymov">RomanPodymov</a> |<a href="https://github.com/schinj">schinj</a> |<a href="https://github.com/cheskapac">cheskapac</a> |<a href="https://github.com/dcramps">dcramps</a> |<a href="https://github.com/euriasb">euriasb</a> |<a href="https://github.com/fossabot">fossabot</a> |</p>
<p>
<a href="https://github.com/ibrahimoktay">&lt;img alt=&quot;ibrahimoktay&quot; src=&quot;https://avatars.githubusercontent.com/u/36792481?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/jimmy-li-houzz">&lt;img alt=&quot;jimmy-li-houzz&quot; src=&quot;https://avatars.githubusercontent.com/u/96756372?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/kimxwan0319">&lt;img alt=&quot;kimxwan0319&quot; src=&quot;https://avatars.githubusercontent.com/u/67373938?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/MariusDeReus">&lt;img alt=&quot;MariusDeReus&quot; src=&quot;https://avatars.githubusercontent.com/u/9931253?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mustiikhalil">&lt;img alt=&quot;mustiikhalil&quot; src=&quot;https://avatars.githubusercontent.com/u/26250654?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ronanociosoig-200">&lt;img alt=&quot;ronanociosoig-200&quot; src=&quot;https://avatars.githubusercontent.com/u/51952707?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/ibrahimoktay">ibrahimoktay</a> |<a href="https://github.com/jimmy-li-houzz">jimmy-li-houzz</a> |<a href="https://github.com/kimxwan0319">kimxwan0319</a> |<a href="https://github.com/MariusDeReus">MariusDeReus</a> |<a href="https://github.com/mustiikhalil">mustiikhalil</a> |<a href="https://github.com/ronanociosoig-200">ronanociosoig-200</a> |</p>
<p>
<a href="https://github.com/sh-a-n">&lt;img alt=&quot;sh-a-n&quot; src=&quot;https://avatars.githubusercontent.com/u/2219548?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/sonuvryahoo">&lt;img alt=&quot;sonuvryahoo&quot; src=&quot;https://avatars.githubusercontent.com/u/61445098?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/vendulasvastal">&lt;img alt=&quot;vendulasvastal&quot; src=&quot;https://avatars.githubusercontent.com/u/42235915?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tatagrigory">&lt;img alt=&quot;tatagrigory&quot; src=&quot;https://avatars.githubusercontent.com/u/5187973?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tuistbot">&lt;img alt=&quot;tuistbot&quot; src=&quot;https://avatars.githubusercontent.com/u/34792320?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tzxdtc">&lt;img alt=&quot;tzxdtc&quot; src=&quot;https://avatars.githubusercontent.com/u/19767846?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/sh-a-n">sh-a-n</a> |<a href="https://github.com/sonuvryahoo">sonuvryahoo</a> |<a href="https://github.com/vendulasvastal">vendulasvastal</a> |<a href="https://github.com/tatagrigory">tatagrigory</a> |<a href="https://github.com/tuistbot">tuistbot</a> |<a href="https://github.com/tzxdtc">tzxdtc</a> |</p>
<p>
<a href="https://github.com/jihoonahn">&lt;img alt=&quot;jihoonahn&quot; src=&quot;https://avatars.githubusercontent.com/u/68891494?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ThiemeFM">&lt;img alt=&quot;ThiemeFM&quot; src=&quot;https://avatars.githubusercontent.com/u/143395823?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/takinwande">&lt;img alt=&quot;takinwande&quot; src=&quot;https://avatars.githubusercontent.com/u/4744429?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tiarnann">&lt;img alt=&quot;tiarnann&quot; src=&quot;https://avatars.githubusercontent.com/u/10522081?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/vkrol">&lt;img alt=&quot;vkrol&quot; src=&quot;https://avatars.githubusercontent.com/u/153412?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/victor-sarda">&lt;img alt=&quot;victor-sarda&quot; src=&quot;https://avatars.githubusercontent.com/u/6460866?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/jihoonahn">jihoonahn</a> |<a href="https://github.com/ThiemeFM">ThiemeFM</a> |<a href="https://github.com/takinwande">takinwande</a> |<a href="https://github.com/tiarnann">tiarnann</a> |<a href="https://github.com/vkrol">vkrol</a> |<a href="https://github.com/victor-sarda">victor-sarda</a> |</p>
<p>
<a href="https://github.com/VilleWitt">&lt;img alt=&quot;VilleWitt&quot; src=&quot;https://avatars.githubusercontent.com/u/522544?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/vcoutasso">&lt;img alt=&quot;vcoutasso&quot; src=&quot;https://avatars.githubusercontent.com/u/44986513?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/in4lio">&lt;img alt=&quot;in4lio&quot; src=&quot;https://avatars.githubusercontent.com/u/976061?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/khramtsoff">&lt;img alt=&quot;khramtsoff&quot; src=&quot;https://avatars.githubusercontent.com/u/3510864?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/SpectralDragon">&lt;img alt=&quot;SpectralDragon&quot; src=&quot;https://avatars.githubusercontent.com/u/6003467?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/wangjiejacques">&lt;img alt=&quot;wangjiejacques&quot; src=&quot;https://avatars.githubusercontent.com/u/2981971?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/VilleWitt">VilleWitt</a> |<a href="https://github.com/vcoutasso">vcoutasso</a> |<a href="https://github.com/in4lio">in4lio</a> |<a href="https://github.com/khramtsoff">khramtsoff</a> |<a href="https://github.com/SpectralDragon">SpectralDragon</a> |<a href="https://github.com/wangjiejacques">wangjiejacques</a> |</p>
<p>
<a href="https://github.com/wojciech-kulik">&lt;img alt=&quot;wojciech-kulik&quot; src=&quot;https://avatars.githubusercontent.com/u/3128467?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Buju77">&lt;img alt=&quot;Buju77&quot; src=&quot;https://avatars.githubusercontent.com/u/266349?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/neakor">&lt;img alt=&quot;neakor&quot; src=&quot;https://avatars.githubusercontent.com/u/1827517?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/zzzkk">&lt;img alt=&quot;zzzkk&quot; src=&quot;https://avatars.githubusercontent.com/u/12541603?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/aegzorz">&lt;img alt=&quot;aegzorz&quot; src=&quot;https://avatars.githubusercontent.com/u/810539?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/aniltaskiran">&lt;img alt=&quot;aniltaskiran&quot; src=&quot;https://avatars.githubusercontent.com/u/16738729?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/wojciech-kulik">wojciech-kulik</a> |<a href="https://github.com/Buju77">Buju77</a> |<a href="https://github.com/neakor">neakor</a> |<a href="https://github.com/zzzkk">zzzkk</a> |<a href="https://github.com/aegzorz">aegzorz</a> |<a href="https://github.com/aniltaskiran">aniltaskiran</a> |</p>
<p>
<a href="https://github.com/abbasmousavi">&lt;img alt=&quot;abbasmousavi&quot; src=&quot;https://avatars.githubusercontent.com/u/1249875?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dbarden">&lt;img alt=&quot;dbarden&quot; src=&quot;https://avatars.githubusercontent.com/u/104456?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/danielmoro">&lt;img alt=&quot;danielmoro&quot; src=&quot;https://avatars.githubusercontent.com/u/6289001?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/DarkoDamjanovic">&lt;img alt=&quot;DarkoDamjanovic&quot; src=&quot;https://avatars.githubusercontent.com/u/11902775?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Primecutz">&lt;img alt=&quot;Primecutz&quot; src=&quot;https://avatars.githubusercontent.com/u/42585232?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/cieslakdawid">&lt;img alt=&quot;cieslakdawid&quot; src=&quot;https://avatars.githubusercontent.com/u/4325222?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/abbasmousavi">abbasmousavi</a> |<a href="https://github.com/dbarden">dbarden</a> |<a href="https://github.com/danielmoro">danielmoro</a> |<a href="https://github.com/DarkoDamjanovic">DarkoDamjanovic</a> |<a href="https://github.com/Primecutz">Primecutz</a> |<a href="https://github.com/cieslakdawid">cieslakdawid</a> |</p>
<p>
<a href="https://github.com/decanus">&lt;img alt=&quot;decanus&quot; src=&quot;https://avatars.githubusercontent.com/u/7621705?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/denil-ct">&lt;img alt=&quot;denil-ct&quot; src=&quot;https://avatars.githubusercontent.com/u/95201442?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/francuim-d">&lt;img alt=&quot;francuim-d&quot; src=&quot;https://avatars.githubusercontent.com/u/86049208?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dxmvsh">&lt;img alt=&quot;dxmvsh&quot; src=&quot;https://avatars.githubusercontent.com/u/44325936?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dever25">&lt;img alt=&quot;dever25&quot; src=&quot;https://avatars.githubusercontent.com/u/32138530?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/navartis">&lt;img alt=&quot;navartis&quot; src=&quot;https://avatars.githubusercontent.com/u/7813723?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/decanus">decanus</a> |<a href="https://github.com/denil-ct">denil-ct</a> |<a href="https://github.com/francuim-d">francuim-d</a> |<a href="https://github.com/dxmvsh">dxmvsh</a> |<a href="https://github.com/dever25">dever25</a> |<a href="https://github.com/navartis">navartis</a> |</p>
<p>
<a href="https://github.com/Dmitry-Pliushchai">&lt;img alt=&quot;Dmitry-Pliushchai&quot; src=&quot;https://avatars.githubusercontent.com/u/59007906?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ElonPark">&lt;img alt=&quot;ElonPark&quot; src=&quot;https://avatars.githubusercontent.com/u/13270453?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/bogren">&lt;img alt=&quot;bogren&quot; src=&quot;https://avatars.githubusercontent.com/u/2457281?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/eito">&lt;img alt=&quot;eito&quot; src=&quot;https://avatars.githubusercontent.com/u/775643?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/MrCloud">&lt;img alt=&quot;MrCloud&quot; src=&quot;https://avatars.githubusercontent.com/u/486140?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/gcacoutinho">&lt;img alt=&quot;gcacoutinho&quot; src=&quot;https://avatars.githubusercontent.com/u/17842860?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/Dmitry-Pliushchai">Dmitry-Pliushchai</a> |<a href="https://github.com/ElonPark">ElonPark</a> |<a href="https://github.com/bogren">bogren</a> |<a href="https://github.com/eito">eito</a> |<a href="https://github.com/MrCloud">MrCloud</a> |<a href="https://github.com/gcacoutinho">gcacoutinho</a> |</p>
<p>
<a href="https://github.com/Smponias">&lt;img alt=&quot;Smponias&quot; src=&quot;https://avatars.githubusercontent.com/u/14213855?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/alvarhansen">&lt;img alt=&quot;alvarhansen&quot; src=&quot;https://avatars.githubusercontent.com/u/482293?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/andruvs">&lt;img alt=&quot;andruvs&quot; src=&quot;https://avatars.githubusercontent.com/u/19372247?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/anlaital-oura">&lt;img alt=&quot;anlaital-oura&quot; src=&quot;https://avatars.githubusercontent.com/u/133648611?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/a-sarris">&lt;img alt=&quot;a-sarris&quot; src=&quot;https://avatars.githubusercontent.com/u/78614622?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Gladkov-Art">&lt;img alt=&quot;Gladkov-Art&quot; src=&quot;https://avatars.githubusercontent.com/u/5657130?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/Smponias">Smponias</a> |<a href="https://github.com/alvarhansen">alvarhansen</a> |<a href="https://github.com/andruvs">andruvs</a> |<a href="https://github.com/anlaital-oura">anlaital-oura</a> |<a href="https://github.com/a-sarris">a-sarris</a> |<a href="https://github.com/Gladkov-Art">Gladkov-Art</a> |</p>
<p>
<a href="https://github.com/astromonkee">&lt;img alt=&quot;astromonkee&quot; src=&quot;https://avatars.githubusercontent.com/u/44421303?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ajevans99">&lt;img alt=&quot;ajevans99&quot; src=&quot;https://avatars.githubusercontent.com/u/30383071?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/batuhansk">&lt;img alt=&quot;batuhansk&quot; src=&quot;https://avatars.githubusercontent.com/u/9626765?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/BenjaminPrieur">&lt;img alt=&quot;BenjaminPrieur&quot; src=&quot;https://avatars.githubusercontent.com/u/4921255?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/bhuemer">&lt;img alt=&quot;bhuemer&quot; src=&quot;https://avatars.githubusercontent.com/u/1212480?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/csjones">&lt;img alt=&quot;csjones&quot; src=&quot;https://avatars.githubusercontent.com/u/637026?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/astromonkee">astromonkee</a> |<a href="https://github.com/ajevans99">ajevans99</a> |<a href="https://github.com/batuhansk">batuhansk</a> |<a href="https://github.com/BenjaminPrieur">BenjaminPrieur</a> |<a href="https://github.com/bhuemer">bhuemer</a> |<a href="https://github.com/csjones">csjones</a> |</p>
<p>
<a href="https://github.com/cconstable">&lt;img alt=&quot;cconstable&quot; src=&quot;https://avatars.githubusercontent.com/u/564781?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/acosmicflamingo">&lt;img alt=&quot;acosmicflamingo&quot; src=&quot;https://avatars.githubusercontent.com/u/67525430?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/cruisediary">&lt;img alt=&quot;cruisediary&quot; src=&quot;https://avatars.githubusercontent.com/u/2609775?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Killectro">&lt;img alt=&quot;Killectro&quot; src=&quot;https://avatars.githubusercontent.com/u/1429690?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/danrevah">&lt;img alt=&quot;danrevah&quot; src=&quot;https://avatars.githubusercontent.com/u/7808742?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/kevinrandrup">&lt;img alt=&quot;kevinrandrup&quot; src=&quot;https://avatars.githubusercontent.com/u/5884570?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/cconstable">cconstable</a> |<a href="https://github.com/acosmicflamingo">acosmicflamingo</a> |<a href="https://github.com/cruisediary">cruisediary</a> |<a href="https://github.com/Killectro">Killectro</a> |<a href="https://github.com/danrevah">danrevah</a> |<a href="https://github.com/kevinrandrup">kevinrandrup</a> |</p>
<p>
<a href="https://github.com/kientux">&lt;img alt=&quot;kientux&quot; src=&quot;https://avatars.githubusercontent.com/u/4200743?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/UniekLee">&lt;img alt=&quot;UniekLee&quot; src=&quot;https://avatars.githubusercontent.com/u/2877482?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/lucabartoletti">&lt;img alt=&quot;lucabartoletti&quot; src=&quot;https://avatars.githubusercontent.com/u/838925?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/luciav-github">&lt;img alt=&quot;luciav-github&quot; src=&quot;https://avatars.githubusercontent.com/u/72014503?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/lm2s">&lt;img alt=&quot;lm2s&quot; src=&quot;https://avatars.githubusercontent.com/u/221489?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mpodeszwa">&lt;img alt=&quot;mpodeszwa&quot; src=&quot;https://avatars.githubusercontent.com/u/7826664?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/kientux">kientux</a> |<a href="https://github.com/UniekLee">UniekLee</a> |<a href="https://github.com/lucabartoletti">lucabartoletti</a> |<a href="https://github.com/luciav-github">luciav-github</a> |<a href="https://github.com/lm2s">lm2s</a> |<a href="https://github.com/mpodeszwa">mpodeszwa</a> |</p>
<p>
<a href="https://github.com/MartinStrambach">&lt;img alt=&quot;MartinStrambach&quot; src=&quot;https://avatars.githubusercontent.com/u/11178869?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/MarvinNazari">&lt;img alt=&quot;MarvinNazari&quot; src=&quot;https://avatars.githubusercontent.com/u/926772?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Mstrodl">&lt;img alt=&quot;Mstrodl&quot; src=&quot;https://avatars.githubusercontent.com/u/6877780?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/MatyasKriz">&lt;img alt=&quot;MatyasKriz&quot; src=&quot;https://avatars.githubusercontent.com/u/6033733?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Speakus">&lt;img alt=&quot;Speakus&quot; src=&quot;https://avatars.githubusercontent.com/u/849294?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/michaelmcguire">&lt;img alt=&quot;michaelmcguire&quot; src=&quot;https://avatars.githubusercontent.com/u/429790?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/MartinStrambach">MartinStrambach</a> |<a href="https://github.com/MarvinNazari">MarvinNazari</a> |<a href="https://github.com/Mstrodl">Mstrodl</a> |<a href="https://github.com/MatyasKriz">MatyasKriz</a> |<a href="https://github.com/Speakus">Speakus</a> |<a href="https://github.com/michaelmcguire">michaelmcguire</a> |</p>
<p>
<a href="https://github.com/michalsrutek">&lt;img alt=&quot;michalsrutek&quot; src=&quot;https://avatars.githubusercontent.com/u/35694712?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mgray88">&lt;img alt=&quot;mgray88&quot; src=&quot;https://avatars.githubusercontent.com/u/411747?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/akaDuality">&lt;img alt=&quot;akaDuality&quot; src=&quot;https://avatars.githubusercontent.com/u/3120680?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/MagnificentMiles">&lt;img alt=&quot;MagnificentMiles&quot; src=&quot;https://avatars.githubusercontent.com/u/151460175?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/gaetanomatonti">&lt;img alt=&quot;gaetanomatonti&quot; src=&quot;https://avatars.githubusercontent.com/u/19956801?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Arclite">&lt;img alt=&quot;Arclite&quot; src=&quot;https://avatars.githubusercontent.com/u/184375?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/michalsrutek">michalsrutek</a> |<a href="https://github.com/mgray88">mgray88</a> |<a href="https://github.com/akaDuality">akaDuality</a> |<a href="https://github.com/MagnificentMiles">MagnificentMiles</a> |<a href="https://github.com/gaetanomatonti">gaetanomatonti</a> |<a href="https://github.com/Arclite">Arclite</a> |</p>
<p>
<a href="https://github.com/mangofever">&lt;img alt=&quot;mangofever&quot; src=&quot;https://avatars.githubusercontent.com/u/724343?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/grdsdev">&lt;img alt=&quot;grdsdev&quot; src=&quot;https://avatars.githubusercontent.com/u/5923044?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Tulleb">&lt;img alt=&quot;Tulleb&quot; src=&quot;https://avatars.githubusercontent.com/u/5658984?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/haeseoklee">&lt;img alt=&quot;haeseoklee&quot; src=&quot;https://avatars.githubusercontent.com/u/20268101?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/eltociear">&lt;img alt=&quot;eltociear&quot; src=&quot;https://avatars.githubusercontent.com/u/22633385?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/woin2ee">&lt;img alt=&quot;woin2ee&quot; src=&quot;https://avatars.githubusercontent.com/u/81426024?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/mangofever">mangofever</a> |<a href="https://github.com/grdsdev">grdsdev</a> |<a href="https://github.com/Tulleb">Tulleb</a> |<a href="https://github.com/haeseoklee">haeseoklee</a> |<a href="https://github.com/eltociear">eltociear</a> |<a href="https://github.com/woin2ee">woin2ee</a> |</p>
<p>
<a href="https://github.com/unxavi">&lt;img alt=&quot;unxavi&quot; src=&quot;https://avatars.githubusercontent.com/u/3817679?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/jesus-mg-ios">&lt;img alt=&quot;jesus-mg-ios&quot; src=&quot;https://avatars.githubusercontent.com/u/85997060?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mo5tone">&lt;img alt=&quot;mo5tone&quot; src=&quot;https://avatars.githubusercontent.com/u/8422976?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/jinuman">&lt;img alt=&quot;jinuman&quot; src=&quot;https://avatars.githubusercontent.com/u/26243835?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Juanpe">&lt;img alt=&quot;Juanpe&quot; src=&quot;https://avatars.githubusercontent.com/u/1409041?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/JulianAlonso">&lt;img alt=&quot;JulianAlonso&quot; src=&quot;https://avatars.githubusercontent.com/u/5766613?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/unxavi">unxavi</a> |<a href="https://github.com/jesus-mg-ios">jesus-mg-ios</a> |<a href="https://github.com/mo5tone">mo5tone</a> |<a href="https://github.com/jinuman">jinuman</a> |<a href="https://github.com/Juanpe">Juanpe</a> |<a href="https://github.com/JulianAlonso">JulianAlonso</a> |</p>
<p>
<a href="https://github.com/nagra">&lt;img alt=&quot;nagra&quot; src=&quot;https://avatars.githubusercontent.com/u/869660?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/avbangar">&lt;img alt=&quot;avbangar&quot; src=&quot;https://avatars.githubusercontent.com/u/52976276?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/kevin58332">&lt;img alt=&quot;kevin58332&quot; src=&quot;https://avatars.githubusercontent.com/u/47673410?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/codeOfRobin">&lt;img alt=&quot;codeOfRobin&quot; src=&quot;https://avatars.githubusercontent.com/u/5009041?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/santos88">&lt;img alt=&quot;santos88&quot; src=&quot;https://avatars.githubusercontent.com/u/144450?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/spqw">&lt;img alt=&quot;spqw&quot; src=&quot;https://avatars.githubusercontent.com/u/101190846?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/nagra">nagra</a> |<a href="https://github.com/avbangar">avbangar</a> |<a href="https://github.com/kevin58332">kevin58332</a> |<a href="https://github.com/codeOfRobin">codeOfRobin</a> |<a href="https://github.com/santos88">santos88</a> |<a href="https://github.com/spqw">spqw</a> |</p>
<p>
<a href="https://github.com/dankinsoid">&lt;img alt=&quot;dankinsoid&quot; src=&quot;https://avatars.githubusercontent.com/u/30962149?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/kyungpyoda">&lt;img alt=&quot;kyungpyoda&quot; src=&quot;https://avatars.githubusercontent.com/u/44656036?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/oozoofrog">&lt;img alt=&quot;oozoofrog&quot; src=&quot;https://avatars.githubusercontent.com/u/3011832?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dp221125">&lt;img alt=&quot;dp221125&quot; src=&quot;https://avatars.githubusercontent.com/u/10572119?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/thelvis4">&lt;img alt=&quot;thelvis4&quot; src=&quot;https://avatars.githubusercontent.com/u/1589385?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/tovkal">&lt;img alt=&quot;tovkal&quot; src=&quot;https://avatars.githubusercontent.com/u/5960675?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/dankinsoid">dankinsoid</a> |<a href="https://github.com/kyungpyoda">kyungpyoda</a> |<a href="https://github.com/oozoofrog">oozoofrog</a> |<a href="https://github.com/dp221125">dp221125</a> |<a href="https://github.com/thelvis4">thelvis4</a> |<a href="https://github.com/tovkal">tovkal</a> |</p>
<p>
<a href="https://github.com/orbitekk">&lt;img alt=&quot;orbitekk&quot; src=&quot;https://avatars.githubusercontent.com/u/4222449?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/woohyunjin06">&lt;img alt=&quot;woohyunjin06&quot; src=&quot;https://avatars.githubusercontent.com/u/30452977?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/lo1tuma">&lt;img alt=&quot;lo1tuma&quot; src=&quot;https://avatars.githubusercontent.com/u/169170?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/softmaxsg">&lt;img alt=&quot;softmaxsg&quot; src=&quot;https://avatars.githubusercontent.com/u/3723817?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/zdnk">&lt;img alt=&quot;zdnk&quot; src=&quot;https://avatars.githubusercontent.com/u/2551911?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Andrea-Scuderi">&lt;img alt=&quot;Andrea-Scuderi&quot; src=&quot;https://avatars.githubusercontent.com/u/8319309?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/orbitekk">orbitekk</a> |<a href="https://github.com/woohyunjin06">woohyunjin06</a> |<a href="https://github.com/lo1tuma">lo1tuma</a> |<a href="https://github.com/softmaxsg">softmaxsg</a> |<a href="https://github.com/zdnk">zdnk</a> |<a href="https://github.com/Andrea-Scuderi">Andrea-Scuderi</a> |</p>
<p>
<a href="https://github.com/roanutil">&lt;img alt=&quot;roanutil&quot; src=&quot;https://avatars.githubusercontent.com/u/9873566?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/cpisciotta">&lt;img alt=&quot;cpisciotta&quot; src=&quot;https://avatars.githubusercontent.com/u/38054839?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/cristi-lupu">&lt;img alt=&quot;cristi-lupu&quot; src=&quot;https://avatars.githubusercontent.com/u/41613812?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/david-all-win-software">&lt;img alt=&quot;david-all-win-software&quot; src=&quot;https://avatars.githubusercontent.com/u/70285087?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/DavidBrunow">&lt;img alt=&quot;DavidBrunow&quot; src=&quot;https://avatars.githubusercontent.com/u/1452879?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dcordero">&lt;img alt=&quot;dcordero&quot; src=&quot;https://avatars.githubusercontent.com/u/2320840?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/roanutil">roanutil</a> |<a href="https://github.com/cpisciotta">cpisciotta</a> |<a href="https://github.com/cristi-lupu">cristi-lupu</a> |<a href="https://github.com/david-all-win-software">david-all-win-software</a> |<a href="https://github.com/DavidBrunow">DavidBrunow</a> |<a href="https://github.com/dcordero">dcordero</a> |</p>
<p>
<a href="https://github.com/dogo">&lt;img alt=&quot;dogo&quot; src=&quot;https://avatars.githubusercontent.com/u/1487375?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/griches">&lt;img alt=&quot;griches&quot; src=&quot;https://avatars.githubusercontent.com/u/798117?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/GermanVelibekovHouzz">&lt;img alt=&quot;GermanVelibekovHouzz&quot; src=&quot;https://avatars.githubusercontent.com/u/81903043?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/PierreCapo">&lt;img alt=&quot;PierreCapo&quot; src=&quot;https://avatars.githubusercontent.com/u/26744253?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/iainsmith">&lt;img alt=&quot;iainsmith&quot; src=&quot;https://avatars.githubusercontent.com/u/993745?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/myihsan">&lt;img alt=&quot;myihsan&quot; src=&quot;https://avatars.githubusercontent.com/u/7414906?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/dogo">dogo</a> |<a href="https://github.com/griches">griches</a> |<a href="https://github.com/GermanVelibekovHouzz">GermanVelibekovHouzz</a> |<a href="https://github.com/PierreCapo">PierreCapo</a> |<a href="https://github.com/iainsmith">iainsmith</a> |<a href="https://github.com/myihsan">myihsan</a> |</p>
<p>
<a href="https://github.com/L-j-h-c">&lt;img alt=&quot;L-j-h-c&quot; src=&quot;https://avatars.githubusercontent.com/u/77208067?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/havebeenfitz">&lt;img alt=&quot;havebeenfitz&quot; src=&quot;https://avatars.githubusercontent.com/u/31866271?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mfcollins3">&lt;img alt=&quot;mfcollins3&quot; src=&quot;https://avatars.githubusercontent.com/u/104274?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/nicholaskim94">&lt;img alt=&quot;nicholaskim94&quot; src=&quot;https://avatars.githubusercontent.com/u/7912759?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/zhuhaow">&lt;img alt=&quot;zhuhaow&quot; src=&quot;https://avatars.githubusercontent.com/u/1287724?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/baekteun">&lt;img alt=&quot;baekteun&quot; src=&quot;https://avatars.githubusercontent.com/u/74440939?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/L-j-h-c">L-j-h-c</a> |<a href="https://github.com/havebeenfitz">havebeenfitz</a> |<a href="https://github.com/mfcollins3">mfcollins3</a> |<a href="https://github.com/nicholaskim94">nicholaskim94</a> |<a href="https://github.com/zhuhaow">zhuhaow</a> |<a href="https://github.com/baekteun">baekteun</a> |</p>
<p>
<a href="https://github.com/jakeatoms">&lt;img alt=&quot;jakeatoms&quot; src=&quot;https://avatars.githubusercontent.com/u/3605966?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/jrescabias">&lt;img alt=&quot;jrescabias&quot; src=&quot;https://avatars.githubusercontent.com/u/78204502?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/danibachar">&lt;img alt=&quot;danibachar&quot; src=&quot;https://avatars.githubusercontent.com/u/6380777?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/apps4everyone">&lt;img alt=&quot;apps4everyone&quot; src=&quot;https://avatars.githubusercontent.com/u/1915802?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/chojnac">&lt;img alt=&quot;chojnac&quot; src=&quot;https://avatars.githubusercontent.com/u/304027?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/shahzadmajeed">&lt;img alt=&quot;shahzadmajeed&quot; src=&quot;https://avatars.githubusercontent.com/u/1209459?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/jakeatoms">jakeatoms</a> |<a href="https://github.com/jrescabias">jrescabias</a> |<a href="https://github.com/danibachar">danibachar</a> |<a href="https://github.com/apps4everyone">apps4everyone</a> |<a href="https://github.com/chojnac">chojnac</a> |<a href="https://github.com/shahzadmajeed">shahzadmajeed</a> |</p>
<p>
<a href="https://github.com/pavel-trafimuk">&lt;img alt=&quot;pavel-trafimuk&quot; src=&quot;https://avatars.githubusercontent.com/u/5096762?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/AlbGarciam">&lt;img alt=&quot;AlbGarciam&quot; src=&quot;https://avatars.githubusercontent.com/u/45308839?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/xoxo-anastasi-xoxo">&lt;img alt=&quot;xoxo-anastasi-xoxo&quot; src=&quot;https://avatars.githubusercontent.com/u/28875920?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/davebcn87">&lt;img alt=&quot;davebcn87&quot; src=&quot;https://avatars.githubusercontent.com/u/477473?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/morozkin">&lt;img alt=&quot;morozkin&quot; src=&quot;https://avatars.githubusercontent.com/u/16591888?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/esttorhe">&lt;img alt=&quot;esttorhe&quot; src=&quot;https://avatars.githubusercontent.com/u/2642850?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/pavel-trafimuk">pavel-trafimuk</a> |<a href="https://github.com/AlbGarciam">AlbGarciam</a> |<a href="https://github.com/xoxo-anastasi-xoxo">xoxo-anastasi-xoxo</a> |<a href="https://github.com/davebcn87">davebcn87</a> |<a href="https://github.com/morozkin">morozkin</a> |<a href="https://github.com/esttorhe">esttorhe</a> |</p>
<p>
<a href="https://github.com/ffittschen">&lt;img alt=&quot;ffittschen&quot; src=&quot;https://avatars.githubusercontent.com/u/7734806?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/FranzBusch">&lt;img alt=&quot;FranzBusch&quot; src=&quot;https://avatars.githubusercontent.com/u/3491887?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Jake-Prickett">&lt;img alt=&quot;Jake-Prickett&quot; src=&quot;https://avatars.githubusercontent.com/u/26095410?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/miscampbell">&lt;img alt=&quot;miscampbell&quot; src=&quot;https://avatars.githubusercontent.com/u/3660489?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/bolismauro">&lt;img alt=&quot;bolismauro&quot; src=&quot;https://avatars.githubusercontent.com/u/771999?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/moritzsternemann">&lt;img alt=&quot;moritzsternemann&quot; src=&quot;https://avatars.githubusercontent.com/u/3034168?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/ffittschen">ffittschen</a> |<a href="https://github.com/FranzBusch">FranzBusch</a> |<a href="https://github.com/Jake-Prickett">Jake-Prickett</a> |<a href="https://github.com/miscampbell">miscampbell</a> |<a href="https://github.com/bolismauro">bolismauro</a> |<a href="https://github.com/moritzsternemann">moritzsternemann</a> |</p>
<p>
<a href="https://github.com/paulsamuels">&lt;img alt=&quot;paulsamuels&quot; src=&quot;https://avatars.githubusercontent.com/u/527091?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/devyhan">&lt;img alt=&quot;devyhan&quot; src=&quot;https://avatars.githubusercontent.com/u/45344633?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/svenmuennich">&lt;img alt=&quot;svenmuennich&quot; src=&quot;https://avatars.githubusercontent.com/u/1932115?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/pewegela">&lt;img alt=&quot;pewegela&quot; src=&quot;https://avatars.githubusercontent.com/u/47323347?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/raven">&lt;img alt=&quot;raven&quot; src=&quot;https://avatars.githubusercontent.com/u/316931?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/MontakOleg">&lt;img alt=&quot;MontakOleg&quot; src=&quot;https://avatars.githubusercontent.com/u/1800899?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/paulsamuels">paulsamuels</a> |<a href="https://github.com/devyhan">devyhan</a> |<a href="https://github.com/svenmuennich">svenmuennich</a> |<a href="https://github.com/pewegela">pewegela</a> |<a href="https://github.com/raven">raven</a> |<a href="https://github.com/MontakOleg">MontakOleg</a> |</p>
<p>
<a href="https://github.com/ladislas">&lt;img alt=&quot;ladislas&quot; src=&quot;https://avatars.githubusercontent.com/u/2206544?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/jeroenleenarts">&lt;img alt=&quot;jeroenleenarts&quot; src=&quot;https://avatars.githubusercontent.com/u/39677?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Rag0n">&lt;img alt=&quot;Rag0n&quot; src=&quot;https://avatars.githubusercontent.com/u/1951128?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/serejahh">&lt;img alt=&quot;serejahh&quot; src=&quot;https://avatars.githubusercontent.com/u/2575555?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/Lilfaen">&lt;img alt=&quot;Lilfaen&quot; src=&quot;https://avatars.githubusercontent.com/u/39119695?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/fila95">&lt;img alt=&quot;fila95&quot; src=&quot;https://avatars.githubusercontent.com/u/7265334?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/ladislas">ladislas</a> |<a href="https://github.com/jeroenleenarts">jeroenleenarts</a> |<a href="https://github.com/Rag0n">Rag0n</a> |<a href="https://github.com/serejahh">serejahh</a> |<a href="https://github.com/Lilfaen">Lilfaen</a> |<a href="https://github.com/fila95">fila95</a> |</p>
<p>
<a href="https://github.com/TheInkedEngineer">&lt;img alt=&quot;TheInkedEngineer&quot; src=&quot;https://avatars.githubusercontent.com/u/13349066?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/freak4pc">&lt;img alt=&quot;freak4pc&quot; src=&quot;https://avatars.githubusercontent.com/u/605076?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/wattson12">&lt;img alt=&quot;wattson12&quot; src=&quot;https://avatars.githubusercontent.com/u/1217873?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mstfy">&lt;img alt=&quot;mstfy&quot; src=&quot;https://avatars.githubusercontent.com/u/5105861?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/erkekin">&lt;img alt=&quot;erkekin&quot; src=&quot;https://avatars.githubusercontent.com/u/701481?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/DimaMishchenko">&lt;img alt=&quot;DimaMishchenko&quot; src=&quot;https://avatars.githubusercontent.com/u/25247301?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/TheInkedEngineer">TheInkedEngineer</a> |<a href="https://github.com/freak4pc">freak4pc</a> |<a href="https://github.com/wattson12">wattson12</a> |<a href="https://github.com/mstfy">mstfy</a> |<a href="https://github.com/erkekin">erkekin</a> |<a href="https://github.com/DimaMishchenko">DimaMishchenko</a> |</p>
<p>
<a href="https://github.com/dcvz">&lt;img alt=&quot;dcvz&quot; src=&quot;https://avatars.githubusercontent.com/u/2475932?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/jsorge">&lt;img alt=&quot;jsorge&quot; src=&quot;https://avatars.githubusercontent.com/u/2585841?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ferologics">&lt;img alt=&quot;ferologics&quot; src=&quot;https://avatars.githubusercontent.com/u/5576161?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/yurapriv">&lt;img alt=&quot;yurapriv&quot; src=&quot;https://avatars.githubusercontent.com/u/7814127?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/maciejpiotrowski89">&lt;img alt=&quot;maciejpiotrowski89&quot; src=&quot;https://avatars.githubusercontent.com/u/2279666?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/dangthaison91">&lt;img alt=&quot;dangthaison91&quot; src=&quot;https://avatars.githubusercontent.com/u/6436310?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/dcvz">dcvz</a> |<a href="https://github.com/jsorge">jsorge</a> |<a href="https://github.com/ferologics">ferologics</a> |<a href="https://github.com/yurapriv">yurapriv</a> |<a href="https://github.com/maciejpiotrowski89">maciejpiotrowski89</a> |<a href="https://github.com/dangthaison91">dangthaison91</a> |</p>
<p>
<a href="https://github.com/frijole">&lt;img alt=&quot;frijole&quot; src=&quot;https://avatars.githubusercontent.com/u/60656?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/leszko11">&lt;img alt=&quot;leszko11&quot; src=&quot;https://avatars.githubusercontent.com/u/23533452?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/iteracticman">&lt;img alt=&quot;iteracticman&quot; src=&quot;https://avatars.githubusercontent.com/u/461805?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/thedavidharris">&lt;img alt=&quot;thedavidharris&quot; src=&quot;https://avatars.githubusercontent.com/u/5666250?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/LorDisturbia">&lt;img alt=&quot;LorDisturbia&quot; src=&quot;https://avatars.githubusercontent.com/u/12445776?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/rowwingman">&lt;img alt=&quot;rowwingman&quot; src=&quot;https://avatars.githubusercontent.com/u/351837?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/frijole">frijole</a> |<a href="https://github.com/leszko11">leszko11</a> |<a href="https://github.com/iteracticman">iteracticman</a> |<a href="https://github.com/thedavidharris">thedavidharris</a> |<a href="https://github.com/LorDisturbia">LorDisturbia</a> |<a href="https://github.com/rowwingman">rowwingman</a> |</p>
<p>
<a href="https://github.com/mikchmie">&lt;img alt=&quot;mikchmie&quot; src=&quot;https://avatars.githubusercontent.com/u/15248837?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/hebertialmeida">&lt;img alt=&quot;hebertialmeida&quot; src=&quot;https://avatars.githubusercontent.com/u/103670?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/regularberry">&lt;img alt=&quot;regularberry&quot; src=&quot;https://avatars.githubusercontent.com/u/565192?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/marciniwanicki">&lt;img alt=&quot;marciniwanicki&quot; src=&quot;https://avatars.githubusercontent.com/u/946649?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/facumenzella">&lt;img alt=&quot;facumenzella&quot; src=&quot;https://avatars.githubusercontent.com/u/1125252?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/hisaac">&lt;img alt=&quot;hisaac&quot; src=&quot;https://avatars.githubusercontent.com/u/923876?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/mikchmie">mikchmie</a> |<a href="https://github.com/hebertialmeida">hebertialmeida</a> |<a href="https://github.com/regularberry">regularberry</a> |<a href="https://github.com/marciniwanicki">marciniwanicki</a> |<a href="https://github.com/facumenzella">facumenzella</a> |<a href="https://github.com/hisaac">hisaac</a> |</p>
<p>
<a href="https://github.com/alexanderwe">&lt;img alt=&quot;alexanderwe&quot; src=&quot;https://avatars.githubusercontent.com/u/12934015?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/adamkhazi">&lt;img alt=&quot;adamkhazi&quot; src=&quot;https://avatars.githubusercontent.com/u/9820670?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/luispadron">&lt;img alt=&quot;luispadron&quot; src=&quot;https://avatars.githubusercontent.com/u/13840545?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/vytis">&lt;img alt=&quot;vytis&quot; src=&quot;https://avatars.githubusercontent.com/u/33914?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/natanrolnik">&lt;img alt=&quot;natanrolnik&quot; src=&quot;https://avatars.githubusercontent.com/u/1164565?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ezraberch">&lt;img alt=&quot;ezraberch&quot; src=&quot;https://avatars.githubusercontent.com/u/49635435?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/alexanderwe">alexanderwe</a> |<a href="https://github.com/adamkhazi">adamkhazi</a> |<a href="https://github.com/luispadron">luispadron</a> |<a href="https://github.com/vytis">vytis</a> |<a href="https://github.com/natanrolnik">natanrolnik</a> |<a href="https://github.com/ezraberch">ezraberch</a> |</p>
<p>
<a href="https://github.com/RomainBoulay">&lt;img alt=&quot;RomainBoulay&quot; src=&quot;https://avatars.githubusercontent.com/u/169323?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/apps/kodiakhq">&lt;img alt=&quot;kodiakhq[bot]&quot; src=&quot;https://avatars.githubusercontent.com/in/29196?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/mollyIV">&lt;img alt=&quot;mollyIV&quot; src=&quot;https://avatars.githubusercontent.com/u/10795657?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/andreacipriani">&lt;img alt=&quot;andreacipriani&quot; src=&quot;https://avatars.githubusercontent.com/u/536929?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/lakpa">&lt;img alt=&quot;lakpa&quot; src=&quot;https://avatars.githubusercontent.com/u/389328?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/olejnjak">&lt;img alt=&quot;olejnjak&quot; src=&quot;https://avatars.githubusercontent.com/u/3148214?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/RomainBoulay">RomainBoulay</a> |<a href="https://github.com/apps/kodiakhq">kodiakhq[bot]</a> |<a href="https://github.com/mollyIV">mollyIV</a> |<a href="https://github.com/andreacipriani">andreacipriani</a> |<a href="https://github.com/lakpa">lakpa</a> |<a href="https://github.com/olejnjak">olejnjak</a> |</p>
<p>
<a href="https://github.com/laxmorek">&lt;img alt=&quot;laxmorek&quot; src=&quot;https://avatars.githubusercontent.com/u/4774319?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/adellibovi">&lt;img alt=&quot;adellibovi&quot; src=&quot;https://avatars.githubusercontent.com/u/67916?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/waltflanagan">&lt;img alt=&quot;waltflanagan&quot; src=&quot;https://avatars.githubusercontent.com/u/398293?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/kwridan">&lt;img alt=&quot;kwridan&quot; src=&quot;https://avatars.githubusercontent.com/u/11914919?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/ollieatkinson">&lt;img alt=&quot;ollieatkinson&quot; src=&quot;https://avatars.githubusercontent.com/u/1382565?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/danyf90">&lt;img alt=&quot;danyf90&quot; src=&quot;https://avatars.githubusercontent.com/u/2794031?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |:---: |:---: |:---: |:---: |
<a href="https://github.com/laxmorek">laxmorek</a> |<a href="https://github.com/adellibovi">adellibovi</a> |<a href="https://github.com/waltflanagan">waltflanagan</a> |<a href="https://github.com/kwridan">kwridan</a> |<a href="https://github.com/ollieatkinson">ollieatkinson</a> |<a href="https://github.com/danyf90">danyf90</a> |</p>
<p>
<a href="https://github.com/pepicrft">&lt;img alt=&quot;pepicrft&quot; src=&quot;https://avatars.githubusercontent.com/u/663605?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |<a href="https://github.com/fortmarek">&lt;img alt=&quot;fortmarek&quot; src=&quot;https://avatars.githubusercontent.com/u/9371695?v=4&amp;s=117&quot; width=&quot;117&quot;/&gt;</a> |
:---: |:---: |
<a href="https://github.com/pepicrft">pepicrft</a> |<a href="https://github.com/fortmarek">fortmarek</a> |</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ We are deprecating tuistenv in favor of Mise ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post, we share why we are deprecating tuistenv in favor of mise, a runtime executor that allows you to manage multiple versions of a tool and activate the right one when you choose a directory in your terminal. ]]></summary>
      <link href="https://tuist.dev/blog/2023/12/15/rtx-default"/>
      <id>https://tuist.dev/blog/2023/12/15/rtx-default</id>
      <updated>Fri, 15 Dec 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
If you&#39;ve used Tuist for a while,
you probably know that Tuist&#39;s default installation installs a version manager,
<code class="inline">tuistenv</code>,
which allows you to install multiple versions of Tuist and switch between them easily.
We built this early in the life of Tuist,
because installation solutions like <a href="https://brew.sh/">Homebrew</a> are not able to install and activate multiple versions of the same tool.</p>
<p>
Using the same Tuist version across environments is important to avoid non-deterministic results across environments.
Do you remember when you used to do <code class="inline">bundle exec pod install</code>?
<a href="https://bundler.io/">Bundler</a>,
Ruby&#39;s official dependency manager,
provides that <code class="inline">exec</code> command to ensure everyone is using the same version pinned in the <code class="inline">Gemfile.lock</code> file.</p>
<p>
As we <a href="/blog/2023/07/26/2023-tuist-direction">shared earlier this year</a>,
one of our focus this years is to make Tuist <strong>sustainable</strong>,
and that means we need to focus on the core features that make Tuist great.
<strong>Version management is not one of them.</strong>
But if Homebrew is not a sensible solution for Tuist,
what could we use instead?</p>
<p>
Luckily, a few years ago I had the opportunity to met with <a href="https://twitter.com/jdxcode">Jeff Dickey</a>.
He&#39;s one of the talented engineers behind <a href="https://oclif.io/">OCLIF</a>,
a framework for building command line interfaces,
and a person I admire for his work on open source and CLI tools.
He told me about a new project of him,
<a href="https://github.com/jdx/mise">mise</a>,
which he describes as a &quot;runtime executor&quot;.
<code class="inline">mise</code> can manage multiple versions of a tool,
and not only that, but activate the right one when you choose a directory in your terminal.
It does it by using a <code class="inline">.tools-version</code> file in the directory,
which contains the version of the tool that should be used in that directory and its subdirectories.
Sounds familiar? We solved the exact same problem with <code class="inline">tuistenv</code> and the <code class="inline">.tuist-version</code> file.
It sounded too good to be true, so we decided to give it a try.</p>
<p>
Tuist <a href="https://github.com/tuist/tuist/blob/main/.tool-versions">uses it</a> to manage and activate versions of <code class="inline">tuist</code> (which we use with Tuist itself), swiftformat, and swiftlint, and it&#39;s been working great so far.
It&#39;s proven to be one of those tools that works so well that you forget it&#39;s there.
<code class="inline">mise</code> includes handy commands like <code class="inline">ls-remote</code>, which lists all the remotely-available versions:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
$ mise ls-remote tuist

3.35.0
3.35.1
3.35.2
3.35.4
3.35.5
3.36.0    </shiki-highlight>
  </div>
</div>
<p>
After thorough usage and having a great experience, we&#39;ve decided to deprecate <code class="inline">tuistenv</code> in favor of <code class="inline">mise</code>.
If you are currently using <code class="inline">tuistenv</code> to manage Tuist versions, we recommend you to migrate to <code class="inline">mise</code> by following the instructions below.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
# Uninstall Tuist
curl -Ls https://uninstall.tuist.io | bash

# Install mise
curl https://mise.jdx.dev/mise-latest-macos-arm64 &gt; ~/bin/mise
chmod +x ~/bin/mise

# Install and activate Tuist
mise install tuist@3.36.0
mise install tuist@3
mise use tuist@3.36.0    </shiki-highlight>
  </div>
</div>
<p>
We&#39;ll continue to support <code class="inline">tuistenv</code> until we release the next major version of Tuist in January, Tuist 4.
We are sharing this early so you have time to migrate and give us feedback.
We belive <code class="inline">mise</code> is the right solution for Tuist. It provides a great developer experience, it&#39;s very well maintained and stable, and most importantly, it&#39;ll allow us to focus on the core features that make Tuist great.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Faster Vapor clean builds with Tuist ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Discover how to boost productivity in server-side Swift development using Vapor with Tuist. Manage dependencies efficiently and optimize build times for better workflow. ]]></summary>
      <link href="https://tuist.dev/blog/2023/12/09/faster-vapor"/>
      <id>https://tuist.dev/blog/2023/12/09/faster-vapor</id>
      <updated>Sat, 09 Dec 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
If you build <strong>server-side apps</strong> with Swift, you likely use the <a href="https://vapor.codes">Vapor</a> framework. For those unfamiliar, Vapor is an excellent framework for building server-side Swift applications. It&#39;s built atop <a href="https://github.com/apple/swift-nio">SwiftNIO</a> and boasts impressive performance. Vapor projects and their dependencies are managed using the <a href="https://www.swift.org/package-manager/">Swift Package Manager</a>. You can open <code class="inline">Package.swift</code> in Xcode to run your project, or alternatively, use other IDEs like <a href="https://code.visualstudio.com">VSCode</a>, which offers robust support for Swift projects through <a href="https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang">extensions</a> and is available on various operating systems.</p>
<p>
When I first tried Vapor, having previously worked with <a href="https://www.ruby-lang.org">Ruby</a> and <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a>, where code is almost instantly hot-reloaded, I was surprised to find that a newly created project took a long time to compile. Swift Package Manager and Xcode can build incrementally after the first build, but clean builds, which are slow, occur more often than desired. This happens in continuous integration (CI) and when developers clear their derived data directory to resolve Xcode issues. This issue isn&#39;t specific to Vapor but affects any Swift Package or Xcode project. It&#39;s one of the reasons we started using Tuist to manage the Tuist project, relegating Swift Package Manager to dependency management only. I was curious to see if Tuist could be used with Vapor projects, and the answer was yes. I&#39;d like to share how you can do the same.</p>
<h2 id="a-tuist-managed-vapor-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
A Tuist-Managed Vapor Project<a href="#a-tuist-managed-vapor-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to A Tuist-Managed Vapor Project"></a></h2>
<p>
If you&#39;re familiar with describing a package in <code class="inline">Package.swift</code>, using Tuist will feel similar. In this case, you describe your project in a <code class="inline">Project.swift</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let project = Project(name: &quot;Hello&quot;,
                      targets: [
                        Target(name: &quot;App&quot;,
                               platform: .macOS,
                               product: .commandLineTool,
                               bundleId: &quot;io.tuist.Vapor&quot;,
                               sources: [&quot;Sources/App/**/*.swift&quot;],
                               dependencies: [.external(name: &quot;Vapor&quot;)])
                      ])    </shiki-highlight>
  </div>
</div>
<p>
Note that the target is a <code class="inline">commandLineTool</code>. Xcode will generate an executable that you can run from the command line. Also, it declares an external dependency on the <code class="inline">Vapor</code> product.</p>
<p>
Tuist provides an alternative solution for managing dependencies, building upon Swift Package Manager. Packages are declared in a <code class="inline">Tuist/Dependencies.swift</code> or <code class="inline">Tuist/Package.swift</code> file, and Tuist uses Swift Package Manager to fetch them. When integrated into your projects, they are converted into standard Xcode projects and targets, giving you more control over the integration and allowing us to optimize and validate the graph.</p>
<p>
Create a <code class="inline">Tuist/Dependencies.swift</code> file like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let dependencies = Dependencies(swiftPackageManager: .init([
    .remote(url: &quot;https://github.com/vapor/vapor.git&quot;, requirement: .upToNextMinor(from: &quot;4.83.1&quot;))
], productTypes: [
    &quot;Atomics&quot;: .framework
]), platforms: Set(arrayLiteral: .macOS))    </shiki-highlight>
  </div>
</div>
<blockquote>
  <p>
We are deprecating <code class="inline">Tuist/Dependencies.swift</code> in favor of <code class="inline">Tuist/Package.swift</code> for better compatibility with dependency updating tools. While we already support it, we recommend using the current interface until both provide a comparable developer experience.  </p>
</blockquote>
<p>
Changing the product type of <code class="inline">Atomics</code> to a dynamic framework is crucial; otherwise, the application will fail at runtime.</p>
<p>
Once you have the <code class="inline">Project.swift</code> and <code class="inline">Tuist/Dependencies.swift</code> files, run <code class="inline">tusit fetch</code> to fetch the dependencies, and <code class="inline">tuist generate</code> to create and open an Xcode project from where you can run your app.</p>
<h2 id="binary-caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
Binary Caching<a href="#binary-caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Binary Caching"></a></h2>
<p>
Until now, everything mentioned is achievable with Swift Package Manager. Suppose you want to avoid compiling dependencies on every clean build. In that case, <code class="inline">tuist cache warm</code> turns every project target into binaries using a fingerprinting mechanism. After running this command, Tuist will compile every target in the graph.</p>
<p>
Once complete, run <code class="inline">tuist generate</code>. By default, it will use the cached binaries for dependencies. Since your project has a single target, that should be the only one with sources.</p>
<h2 id="modular-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Modular Architecture<a href="#modular-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Modular Architecture"></a></h2>
<p>
Binary caching also applies to your targets, but it requires a modular architecture to be effective. We recommend splitting your target into smaller ones so that targets depend on other targets&#39; interfaces, avoiding a single target with numerous dependencies. Both Swift Package Manager and Tuist make maintaining a project with many targets easier, so don&#39;t hesitate to have multiple targets. Then, invoke Tuist, specifying the targets you want to focus on:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate Settings Documentation    </shiki-highlight>
  </div>
</div>
<p>
Tuist will include the sources of these targets and attempt to use binaries for everything else, including your project targets.</p>
<p>
If you wish to share binaries across environments, use <a href="https://docs.tuist.dev/en/guides/develop/cache">Tuist Cache</a>. Sign in with <code class="inline">tuist auth login</code> and create your projects. Your CI times, and consequently costs, will significantly reduce, sometimes by up to 80%.</p>
<h2 id="linux" tabindex="-1" class="marketing__blog_post__body__content__heading">
Linux<a href="#linux" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Linux"></a></h2>
<p>
Tuist works with Xcode projects, targeting Apple platforms. However, you&#39;ll likely want to run your Vapor app on Linux. Therefore, we recommend maintaining a CI pipeline that ensures your app and tests compile and run on Linux. To keep CI times low on pull requests (PRs), consider setting up the pipeline to run on <code class="inline">main</code>, automatically reverting PRs if regressions are detected.</p>
<h2 id="conclusion" tabindex="-1" class="marketing__blog_post__body__content__heading">
Conclusion<a href="#conclusion" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Conclusion"></a></h2>
<p>
The productivity gains from using Tuist extend beyond Vapor apps to any Swift Package or Xcode project. Many organizations don&#39;t realize the cost of slow builds until they start using Tuist. Others switch from Swift to other languages or ecosystems with better build times. Our goal is to change this by simplifying the adoption and use of these improvements. Check out <a href="https://github.com/tuist/tuist-vapor-example">this project</a> to see the concepts discussed here in action.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Etsy's Journey with Tuist: A Deep Dive into Modularity and Rapid Iteration ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Etsy evolves its decade-long monolithic iOS app with Tuist, paving the way for modular development. With nearly 50 iOS engineers, they leverage Tuist for streamlined module creation and emphasize a unified approach to architecture. Transitioning to SwiftUI and adopting Preview Driven Development, Etsy champions rapid iteration, testability, and consistent quality. Their tech journey reflects innovation at its best.  ]]></summary>
      <link href="https://tuist.dev/blog/2023/11/30/etsy-and-tuist"/>
      <id>https://tuist.dev/blog/2023/11/30/etsy-and-tuist</id>
      <updated>Thu, 30 Nov 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<a href="https://www.etsy.com/">Etsy</a>, a global marketplace for handmade, vintage, and creative goods has consistently been exploring innovative ways to refine our craft. Historically, this commitment has translated into practices like seamless continuous deployment for both web and mobile applications, along with the implementation of blameless post-mortems. Today, they embody this commitment by embracing Tuist and the principles of modularity, driving them forward in their pursuit of engineering excellence.
With a substantial iOS engineering team and a history spanning a decade with a monolithic app, Etsy’s recent shift towards modularity presents an intriguing case study. It demonstrates how Tuist plays a pivotal role in facilitating this transformation and expanding their iOS project.</p>
<h2 id="organization-and-team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Organization and Team Structure<a href="#organization-and-team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Organization and Team Structure"></a></h2>
<p>
<strong>Could you shed light on the current composition and structure of Etsy’s iOS team, particularly focusing on its size and functionality?</strong></p>
<p>
Our iOS team at Etsy is growing towards 50 engineers, where ~25% are primarily focused on platform support for the remaining 75%, who are distributed across various product teams. These product teams are quite dynamic, blending the expertise of product managers, designers, and engineers from other platforms to function seamlessly.</p>
<h2 id="development-environment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Development Environment<a href="#development-environment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Development Environment"></a></h2>
<p>
<strong>How does Etsy’s iOS team manage the development environment and reduce barriers to code commits?</strong></p>
<p>
We are deeply invested in making the development environment as friendly and barrier-free as possible. We place a huge emphasis on automating most of the machine setup so that developers can start building and running projects almost instantly. Although Xcode is fundamental, other tools like <a href="https://fastlane.tools/">Fastlane</a> significantly aid in CI orchestration and certificate management. Additionally, we maintain an in-house Swift CLI package to build custom CI functionalities, manage build logs, and interact with <a href="https://cloud.google.com/">Google Cloud</a> for screenshot testing, among other tasks.
After a basic installation, scripts automate the rest, ensuring that tools like Tuist and Ruby, specified in their <code class="inline">.ruby_version</code> file, are properly set up.</p>
<h2 id="project-architecture:-from-monolith-to-modules" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project Architecture: From Monolith to Modules<a href="#project-architecture:-from-monolith-to-modules" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project Architecture: From Monolith to Modules"></a></h2>
<h3 id="tuist’s-role-in-modularity" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist’s Role in Modularity<a href="#tuist’s-role-in-modularity" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist’s Role in Modularity"></a></h3>
<p>
<strong>Could you elaborate on how Tuist has influenced Etsy’s modular development and its impact on engineer contribution to architecture?</strong></p>
<p>
Our iOS app was a monolith for nearly a decade. As we scaled, modularity became essential. Today, our transition is well underway, moving from a single block to a component-based architecture. The journey began with just five modules, but today we boast 35 modules, with more in the pipeline.</p>
<p>
We promote a democratic approach where any engineer can contribute to the architecture or introduce new modules. Through what we describe as a <a href="https://martinfowler.com/articles/scaling-architecture-conversationally.html">“conversational approach to architecture,”</a> we aim to align individual decisions with larger architectural goals.</p>
<p>
Tuist became an integral part of our modularity journey. It empowered any engineer, irrespective of their experience with Apple frameworks or dependency management, to create a module. With Tuist’s swift interface, the complexity of framework creation and dependency management became a thing of the past, allowing engineers to center their attention on the business domain problems.</p>
<p>
One thing we hope for is more customizability from Tuist, like defining custom focus modes. This would simplify tasks for engineers and abstract away unnecessary implementation details.</p>
<blockquote>
  <p>
Tuist empowered any engineer, irrespective of their experience with Apple frameworks or dependency management, to create a module.  </p>
</blockquote>
<h3 id="leveraging-tuist’s-project-description-helpers" tabindex="-1" class="marketing__blog_post__body__content__heading">
Leveraging Tuist’s Project Description Helpers<a href="#leveraging-tuist’s-project-description-helpers" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Leveraging Tuist’s Project Description Helpers"></a></h3>
<p>
<strong>How does Etsy ensure consistent and streamlined module creation?</strong></p>
<p>
To streamline the creation of modules, we devised a <code class="inline">Module</code> protocol. It provides a blueprint for engineers to follow, and it also offers default functionalities for things like test targets and demo apps. This standardized approach ensures uniformity while also providing flexibility for custom implementations.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
/// A module defines a paved path for creating Tuist targets and accompanying helper targets
public protocol Module {

    /// Name of the module. e.g. &quot;CoreEtsy&quot;
    var moduleName: String { get }

    /// Root path of the module relative to the repository root
    var rootPath: Path { get }

    /// Main target provided by this module. Usually a framework but could be any target built with `TargetBuilder`
    var mainTarget: TargetBuilder { get }

    /// An optional target defining a demo app for the module. Defaults to `.swiftUIDemoApp`. Override to ignore or specify `.uiKitDemoApp`
    var demoAppTarget: TargetBuilder? { get }

    /// An array of targets defining automated tests for this module.  Defaults to a single unit test target. Override to modify or add other test targets like `.uiTestTarget`
    var testTargets: [TargetBuilder] { get }
    /// An array of ResourceSynthesizer to be used with default `Project`
    var resourceSynthesizers: [ResourceSynthesizer] { get }
}    </shiki-highlight>
  </div>
</div>
<h2 id="code-practices-and-dependency-management" tabindex="-1" class="marketing__blog_post__body__content__heading">
Code Practices and Dependency Management<a href="#code-practices-and-dependency-management" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Code Practices and Dependency Management"></a></h2>
<p>
<strong>How does Etsy manage dependencies and navigate the choice of architectural practices for its iOS app?</strong></p>
<p>
While <a href="https://www.objc.io/issues/13-architecture/viper/">VIPER</a> was a mainstay in our iOS app, we’re now gravitating towards more modular and composable architectures, especially with the growing adoption of <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>. Our framework choices revolve around common components like <a href="https://developer.apple.com/documentation/uikit">UIKit</a>, with some functionalities tapping into <a href="https://developer.apple.com/augmented-reality/">ARKit</a> for immersive shopping experiences. In terms of external dependencies, we keep it minimal, focusing on essential frameworks like <a href="https://github.com/kean/Nuke">Nuke</a> for image handling and Lottie for animations. We harness both <a href="https://www.swift.org/package-manager/">Swift Package Manager</a> and <code class="inline">Dependencies.swift</code> for dependency management.</p>
<h2 id="processes:-from-development-to-deployment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Processes: From Development to Deployment<a href="#processes:-from-development-to-deployment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Processes: From Development to Deployment"></a></h2>
<h3 id="releases-and-distribution" tabindex="-1" class="marketing__blog_post__body__content__heading">
Releases and Distribution<a href="#releases-and-distribution" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Releases and Distribution"></a></h3>
<p>
<strong>What is the frequency of your releases internally and to production? Could you outline the process, tools, and key personnel involved in it?</strong></p>
<p>
We recently transitioned from bi-weekly to weekly releases. The process is designed to automate tedious tasks while maintaining engineer involvement throughout. Before each release, engineers review their commits to ensure they align with the intended outcomes. Before branch cut, engineers verify that the code they committed is what they intend to ship (just a simple review to ensure you find everything you expect and nothing unexpected).</p>
<p>
On release days, engineers watch our deployment graphs and analytics pipelines to ensure their features are working as expected and that the release is behaving as expected in production.</p>
<p>
To boost agility, we encourage frequent commits to the main branch, discouraging long-running branches. Every group of pushes to <code class="inline">main</code> creates a new internal build available to all of Etsy and internal users are able to toggle on any features they want to test or verify.</p>
<p>
Additionally, any PR has the ability to create an installable build that can be shared with a link. This allows engineers to share builds with designers and PMs of work in progress to get stakeholder feedback as fast as possible.</p>
<h3 id="preview-driven-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Preview Driven Development<a href="#preview-driven-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Preview Driven Development"></a></h3>
<p>
<strong>How do you ensure rapid iteration cycles when developing new features?</strong></p>
<p>
In our journey towards modularization, we have been leaning towards something called “Preview Driven Development”. As the team went into crafting modules – which were deliberately kept small, purpose-driven, and purely Swift-based – we enjoyed notably fast compile times. This speedy compilation eased up the usage of <a href="https://developer.apple.com/documentation/swiftui/previews-in-xcode">SwiftUI Previews</a>, without being held back by our legacy monolithic codebase.</p>
<p>
We also built a UIKit preview wrapper which lets engineers wrap UIKit views right into SwiftUI Previews. So, no matter which UI technology an engineer decides to use, previews are always an option. Opting to build with previews right from the get-go means creating components that aren’t tied down to network models or real-world data. This is a game-changer, especially when working on features that need specific data to be tested –like an account with a purchase being delivered.</p>
<p>
Preview driven development not only improves our iteration speed just by saving time on compiles and navigating in the app, it also sets us up for future success by helping us build testable code. If our architecture is set up to be previewable with arbitrarily injected data, we can also use that same data in unit tests, helping protect against future regressions.</p>
<h2 id="conclusion" tabindex="-1" class="marketing__blog_post__body__content__heading">
Conclusion<a href="#conclusion" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Conclusion"></a></h2>
<p>
Etsy’s journey is a testament to how organizations can evolve while retaining their core strengths. Their transition to modularity, backed by Tuist, is setting the stage for a future where innovation, speed, and quality go hand in hand.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 3.33.0 and XcodeProj-native support for Swift Macros ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ We released a new version of Tuist, which includes XcodeProj-native support for Swift Macros ]]></summary>
      <link href="https://tuist.dev/blog/2023/11/15/xcode-proj-support-for-macros"/>
      <id>https://tuist.dev/blog/2023/11/15/xcode-proj-support-for-macros</id>
      <updated>Wed, 15 Nov 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/">Swift Macros</a> were introduced, there was widespread excitement about the possibilities they enabled. Developers could now write Swift code that would modify other Swift code at compile-time. To support this feature, Apple chose to adopt <a href="https://developer.apple.com/documentation/xcode/swift-packages">Swift Packages</a> as a bundle and distribution format.</p>
<p>
While this integration made sense on a smaller scale, <strong>it also inherited the same challenges as Swift Packages</strong> and Xcode&#39;s proposal for their integration when applied to large projects. These challenges included getting invalidated during Xcode cleaning, leaving Xcode in an invalid state after manually cleaning derived data, and requiring the compilation of transitive dependencies during clean builds.</p>
<p>
Tuist addressed these challenges by integrating dependencies using Xcode projects and their primitives. In essence, Tuist <strong>converted packages into standard targets and projects and then added the necessary links</strong>. This approach combined the best aspects of the Swift Package Manager and <a href="https://cocoapods.org">CocoaPods</a> worlds, providing access to a vibrant ecosystem of Swift Packages while integrating them in a way that gave developers the control and flexibility needed at a larger scale. Additionally, it offered the added benefit of being cacheable as binaries.</p>
<p>
While this approach worked well for packages used at runtime by the targets, a question arose: <strong>could the same be done for Swift Macros?</strong> I&#39;m pleased to share that the answer is yes, and it feels truly magical. It&#39;s part of the new release of Tuist, <a href="https://github.com/tuist/tuist/releases/tag/3.33.0">Tuist 3.33.0</a></p>
<p>
In essence, <strong>a Swift Macro is a combination of a static and an executable.</strong> The former represents the public interface of the Swift Macro, and its module must be visible to the module depending on the macro. The latter contains the actual logic of the macro and needs to be referenced through a Swift compiler flag when compiling the target that depends on the macro. By converting these elements into XcodeProj targets and adding the necessary glue code, Swift Macros can work just like any other standard XcodeProj target. Isn&#39;t that cool? We&#39;ll soon add support for caching them because <em>who wants to recompile those dependencies every time if the code rarely changes?</em></p>
<p>
If you need assistance with integrating Swift Macros into your project, you can refer to <a href="https://github.com/tuist/tuist/tree/main/examples/xcode/generated_framework_with_native_swift_macro">this project as a reference</a>. Please give it a try, and if something doesn&#39;t work as expected, don&#39;t hesitate to let us know.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist Cloud public beta is here ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist Cloud's public beta is here, offering innovative solutions for Xcode projects. Free for open-source, with exciting plans post-beta in 2024. ]]></summary>
      <link href="https://tuist.dev/blog/2023/11/14/cloud-beta-available"/>
      <id>https://tuist.dev/blog/2023/11/14/cloud-beta-available</id>
      <updated>Tue, 14 Nov 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In our ongoing quest to revolutionize the world of Xcode development, we&#39;ve moved beyond just addressing <a href="https://github.com/tuist/xcodeproj">XcodeProj</a> conflicts and the complexities of modular project maintenance. We discovered that the explicit graphs provided by developers, enriched with our extensive knowledge and models, are vital in empowering teams to overcome a broad spectrum of challenges. These include <strong>enhancing productivity and making strategic, healthful decisions for project evolution.</strong> We&#39;ve crafted <a href="https://tuist.io/cloud">Tuist Cloud</a>,  new extension of Tuist, tailored for teams aspiring to elevate their app development process while optimizing costs and time efficiency.</p>
<p>
<strong>I am thrilled to announce that Tuist Cloud is now entering its public beta phase, accessible for free to all Tuist users.</strong></p>
<h2 id="what-is-tuist-cloud" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is Tuist Cloud<a href="#what-is-tuist-cloud" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is Tuist Cloud"></a></h2>
<h3 id="transformative-binary-caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
Transformative Binary Caching<a href="#transformative-binary-caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Transformative Binary Caching"></a></h3>
<p>
Tuist Cloud <strong>introduces an array of new workflows and enhancements</strong>. Its flagship feature, binary caching, revolutionizes project graph management by caching targets as binaries, streamlining generated projects. This not only benefits local development but also extends its advantages to team members and CI environments, significantly reducing time and costs. Moreover, it seamlessly integrates with <a href="https://developer.apple.com/documentation/xcode/swift-packages">Swift Packages</a> and soon, <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/">Swift Macros</a>, eliminating redundant target compilations in every clean build.</p>
<blockquote>
  <p>
We saw a huge benefit to using tuist locally for the last 6-8 months for project generation and modularisation, but Tuist Cloud is a game changer for us. We were actively considering moving to <a href="https://bazel.build">Bazel</a> for extreme module caching as we will soon be scaling the team, I think Tuist saved us a lot of time not only on CI/Development but with the potential Bazel migration - <a href="https://www.linkedin.com/in/alexanderjameslittle">Alex Little</a> - Head of iOS at <a href="https://www.lapse.com">Lapse</a>  </p>
</blockquote>
<h3 id="incremental-workflows:-bridging-environments" tabindex="-1" class="marketing__blog_post__body__content__heading">
Incremental Workflows: Bridging Environments<a href="#incremental-workflows:-bridging-environments" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Incremental Workflows: Bridging Environments"></a></h3>
<p>
Our commitment extends to what we term <strong>incremental workflows across environments</strong>. Utilizing our fingerprinting technology, used in caching, we pinpoint precisely what needs building or testing. This approach is a game-changer for large codebases, where building and testing everything per commit prolongs feedback cycles. Tuist and Tuist Cloud identify and focus only on the impacted tests and targets, simplifying your workflow without the need for additional tools. We take over the complexity from your pipelines and automations, allowing you to concentrate on what truly matters.</p>
<h3 id="empowering-teams-with-actionable-data" tabindex="-1" class="marketing__blog_post__body__content__heading">
Empowering Teams with Actionable Data<a href="#empowering-teams-with-actionable-data" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Empowering Teams with Actionable Data"></a></h3>
<p>
In the realm of Xcode project evolution, teams often navigate blindly, lacking critical data for informed decision-making. Tuist Cloud aims to change this, by offering tools and metrics to help you with necessary changes to optimize caching efficiency, identify flaky tests impacting team productivity, and more. Our initial dashboard is just the beginning, as we plan to expand it with deeper insights and data based on what you, our users, need.</p>
<h2 id="embrace-tuist-cloud-today" tabindex="-1" class="marketing__blog_post__body__content__heading">
Embrace Tuist Cloud Today<a href="#embrace-tuist-cloud-today" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Embrace Tuist Cloud Today"></a></h2>
<p>
Embark on this journey with Tuist Cloud right now. Create an account and kickstart your project with a few simple commands:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist cloud auth
tuist cloud init    </shiki-highlight>
  </div>
</div>
<p>
Once initialized, you can prime the cache with tuist cache warm, followed by project generation with tuist generate. Tuist defaults to using cache for dependencies, with options to target specific dependencies or opt-out of caching entirely:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist cache warm
tuist generate # Only dependencies from the cache
tuist generate MyTarget # Dependencies + MyTarget dependencies from the cache
tuist generate --no-cache # Disables the cache    </shiki-highlight>
  </div>
</div>
<h2 id="next-steps" tabindex="-1" class="marketing__blog_post__body__content__heading">
Next steps<a href="#next-steps" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Next steps"></a></h2>
<p>
We&#39;re excited for you to try Tuist Cloud and we&#39;d love to hear what you think about it. It&#39;s important for us to get <a href="mailto:contact@tuist.dev"><strong>feedback from users</strong></a> like you as we continue to improve and evolve the tool. Don&#39;t forget to check out <a href="https://docs.tuist.io/cloud/get-started">the documentation</a> to learn more about Tuist Cloud.</p>
<p>
Please note that starting January 2024, after the beta period, Tuist Cloud will become a paid product. The pricing will be based on how much you use the cache, which is part of our plan to make sure Tuist can keep improving for a long time.</p>
<p>
In addition, <strong>Tuist Cloud will be free for open source projects</strong>, which is our way of supporting the wider developer community.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Introducing TuistGPT and XcodeGPT ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist, born in 2017, addresses challenges in scaling Xcode projects. Despite new tools like the Swift Package Manager, the need for Tuist persists. ]]></summary>
      <link href="https://tuist.dev/blog/2023/11/10/gpts"/>
      <id>https://tuist.dev/blog/2023/11/10/gpts</id>
      <updated>Fri, 10 Nov 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Throughout our journey in developing Tuist, <strong>we have accumulated extensive knowledge about the intricacies of Xcode and its project structures.</strong> This expertise was hard-earned, requiring thorough exploration of XcodeProj&#39;s inner workings, delving into various codebases, and crafting Xcode projects that encompass a wide range of complex dependency graphs. We have endeavored to share this wealth of information through blog posts and Tuist&#39;s comprehensive documentation. Despite our efforts to optimize these resources for search engine discoverability, accessing this information remained a challenge.</p>
<p>
Recently, however, <a href="https://openai.com/blog/new-models-and-developer-products-announced-at-devday"><strong>OpenAI&#39;s groundbreaking advancements</strong></a> offer a promising solution to this issue. They have unveiled the concept of specialized GPTs – intelligent assistants tailored to specific domains. Excitingly, we have harnessed this technology to create <strong>XcodeGPT</strong> and <strong>TuistGPT</strong>, tools specifically designed for the Xcode and Tuist communities.</p>
<h3 id="xcodegpt" tabindex="-1" class="marketing__blog_post__body__content__heading">
XcodeGPT<a href="#xcodegpt" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to XcodeGPT"></a></h3>
<p>
XcodeGPT is your go-to assistant for any queries about Xcode, its build systems, and project management. This model is not only trained with publicly available Xcode data but also infused with the nuanced understanding we have developed over the years. We are committed to continually updating XcodeGPT with our latest insights, ensuring it remains an invaluable resource for the most current Xcode information.</p>
<p>
Experience XcodeGPT in action <a href="https://chat.openai.com/g/g-z9dLWHPID-xcodegpt">here</a>.</p>
<h3 id="tuist-gpt" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist GPT<a href="#tuist-gpt" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist GPT"></a></h3>
<p>
Designed with both beginners and experienced users in mind, TuistGPT is your expert guide to all things related to Tuist. It&#39;s enriched with Tuist’s detailed documentation and internal resources, enabling it to offer in-depth knowledge about the project.</p>
<p>
  <img src="/marketing/images/blog/2023/11/10/gpts/tuist-gpt.png" alt="An image that shows an example of a question asked to TuistGPT">
</p>
<p>
Experience TuistGPT in action <a href="https://chat.openai.com/g/g-06dgAxNvw-tuistgpt">here</a>.</p>
<h3 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h3>
<p>
The emergence of large language models is reshaping our interaction with technology in profound ways. We are thrilled to be at the forefront of this technological revolution. Working with Xcode or understanding Tuist can be daunting, but with the advent of GPTs, these challenges are becoming a thing of the past. We are excited to <strong>empower our community with these advanced tools</strong>, making the experience more accessible and less intimidating.</p>
<p>
Looking ahead, we are exploring ways to <strong>integrate these GPTs directly into our documentation</strong>. This will not only streamline access to vital information but also create a more interactive and responsive user experience. Stay tuned as we continue to innovate and bring these cutting-edge AI integrations to our documentation, further enhancing your journey with Tuist and Xcode.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Glovo’s Large-Scale App Development: An In-Depth Look ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Glovo's app development focuses on modular architecture, efficient processes, and a robust team to ensure a top-tier digital experience. ]]></summary>
      <link href="https://tuist.dev/blog/2023/11/03/glovo"/>
      <id>https://tuist.dev/blog/2023/11/03/glovo</id>
      <updated>Fri, 03 Nov 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
<strong>This interview has been edited by <a href="https://www.linkedin.com/in/mariajosesalmeron/">María José Salmerón</a></strong></p>
<p>
In today’s fast-paced digital ecosystem, maintaining a top-tier app requires more than just a great user interface. For companies like <a href="https://glovoapp.com/">Glovo</a>, the magic lies in a blend of innovative architecture, streamlined processes, and a dedicated team. In this interview, we look into the intricate world of Glovo’s iOS development. From modular project structures to efficient testing strategies, we will discover how one of the world’s leading on-demand delivery services crafts its digital experience.</p>
<h2 id="organizational-overview" tabindex="-1" class="marketing__blog_post__body__content__heading">
Organizational Overview<a href="#organizational-overview" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Organizational Overview"></a></h2>
<h4 id="how-is-the-ios-development-team-at-glovo-structured?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How is the iOS development team at Glovo structured?<a href="#how-is-the-ios-development-team-at-glovo-structured?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How is the iOS development team at Glovo structured?"></a></h4>
<p>
At Glovo we have a team of over <strong>30 iOS engineers</strong>. These engineers collaborate within multi-disciplinary teams, encompassing UX, <a href="https://www.android.com">Android</a>, and <a href="https://en.wikipedia.org/wiki/IOS">iOS</a> expertise. We have two user facing apps: <strong>Customer</strong> and <strong>Courier</strong>. While most teams specialize in just one of these apps, the <strong>Platform team</strong> is an exception as we not only contribute to all apps and libraries, but we also develop tools for developers and oversee the maintenance of our CI infrastructure.</p>
<h2 id="development-environment:-balancing-freedom-and-consistency" tabindex="-1" class="marketing__blog_post__body__content__heading">
Development Environment: Balancing Freedom and Consistency<a href="#development-environment:-balancing-freedom-and-consistency" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Development Environment: Balancing Freedom and Consistency"></a></h2>
<h4 id="what-tools,-apart-from-xcode,-do-the-developers-at-glovo-rely-on?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What tools, apart from Xcode, do the developers at Glovo rely on?<a href="#what-tools,-apart-from-xcode,-do-the-developers-at-glovo-rely-on?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What tools, apart from Xcode, do the developers at Glovo rely on?"></a></h4>
<p>
Our iOS developers utilize an array of tools including <a href="https://github.com/fastlane/fastlane">Fastlane</a>, <a href="https://github.com/yonaskolb/XcodeGen">Xcodegen</a>, <a href="https://github.com/SwiftGen/SwiftGen">Swiftgen</a>, <a href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a>, <a href="https://github.com/XcodesOrg/xcodes">xcodes</a>, and <a href="https://github.com/CocoaPods/CocoaPods">Cocoapods</a>. These tools are provisioned through methods such as <a href="https://brew.sh">Homebrew</a> and scripts that engineers can run to get all the tooling installed and set up.</p>
<p>
For <strong>Ruby</strong>, we suggest engineers utilize environment files such as <code class="inline">.rbenv</code> or <code class="inline">.tool-versions</code>. However, developers are welcome to configure their setup as they prefer and can use alternative runtime version managers like <a href="https://asdf-vm.com">asdf</a>.</p>
<p>
Regarding <a href="https://en.wikipedia.org/wiki/Xcode">Xcode</a>, while we don&#39;t mandate a particular version for our engineers, we do have an <code class="inline">.xcode-version</code> file for CI purposes. We advise engineers to adhere to this version to take advantage of cache reuse from CI builds, but it&#39;s not a strict requirement at this time.</p>
<h2 id="modular-project-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Modular Project Architecture<a href="#modular-project-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Modular Project Architecture"></a></h2>
<h4 id="could-you-elaborate-on-glovo's-modular-project-architecture-and-its-foundations?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you elaborate on Glovo&#39;s modular project architecture and its foundations?<a href="#could-you-elaborate-on-glovo's-modular-project-architecture-and-its-foundations?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you elaborate on Glovo's modular project architecture and its foundations?"></a></h4>
<p>
Our focus is on a modular architecture, prioritizing a flat module graph to reduce build times. This architecture aids in parallel module building and lessens the code rebuild frequency when module changes occur. Our modules come in different types: <code class="inline">Implementation</code>, <code class="inline">API</code>, <code class="inline">Shared Types</code>, <code class="inline">InDebt</code>, and <code class="inline">Testing</code>. Each has its purpose and strict relationship rules, ensuring consistency across the project. The compliance of these rules is validated during build time.</p>
<p>
Further details on this topic can be found <a href="https://www.droidcon.com/2022/11/15/modularization-flatten-your-graph-and-get-the-real-benefits/">in a presentation</a> given by my teammate, <a href="https://twitter.com/josef_raska">Josef Raska</a>, at <a href="https://www.droidcon.com">Droidcon</a>.</p>
<h4 id="how-does-the-ios-architecture-compare-with-android,-and-how-is-consistency-maintained?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How does the iOS architecture compare with Android, and how is consistency maintained?<a href="#how-does-the-ios-architecture-compare-with-android,-and-how-is-consistency-maintained?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How does the iOS architecture compare with Android, and how is consistency maintained?"></a></h4>
<p>
The overarching architecture is mirrored for both platforms. Although the tools differ (a Gradle plugin for Android and a Swift Package for iOS), both are rigorously tested to guarantee consistent behavior.</p>
<h4 id="who-can-modify-the-architecture,-like-adding-new-modules?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Who can modify the architecture, like adding new modules?<a href="#who-can-modify-the-architecture,-like-adding-new-modules?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Who can modify the architecture, like adding new modules?"></a></h4>
<p>
Engineers are welcome to propose new modules, as long as they adhere to our guidelines and there&#39;s a clear rationale for the addition.</p>
<p>
Through extensive research, we&#39;ve assessed the impact of adding a module on both iOS and Android platforms. Factors like its effect on app launch times, required storage on a computer, and feedback from developers (for instance, how adding more modules can slow down Android Studio Sync) were considered. Our findings revealed that introducing modules isn&#39;t without costs. Developers should carefully weigh the need to separate specific code into its own module. As a rule of thumb, <strong>we steer clear of very small modules, typically those with less than 1,000 lines of code.</strong></p>
<p>
When suggesting a new module type, it&#39;s essential to undergo a detailed peer review. We have well-defined beliefs about module types, backed by solid reasoning. Any addition of a new type demands peer validation and a robust justification. Since we started our modularization efforts, we&#39;ve incorporated two new types: <code class="inline">InDebt</code> and <code class="inline">Testing</code>. We also have a dedicated Slack channel to foster discussions about modularization, ensuring our architectural direction remains consistent.</p>
<h4 id="what-challenges-come-with-maintaining-and-evolving-this-modular-architecture?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What challenges come with maintaining and evolving this modular architecture?<a href="#what-challenges-come-with-maintaining-and-evolving-this-modular-architecture?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What challenges come with maintaining and evolving this modular architecture?"></a></h4>
<p>
One of our main challenges is to maintain consistent architecture across various apps and platforms while also ensuring a positive developer experience. To achieve this, we use internal tools to ensure module consistency. Additionally, we employ a mix of custom and third-party solutions to monitor build times and prevent setbacks. On the Android side, we trust <a href="https://gradle.com">Gradle Enterprise</a>. Meanwhile, for iOS, we&#39;ve developed a unique tool largely influenced by <a href="https://xcmetrics.io/">Spotify&#39;s XCMetrics</a>. This tool processes Xcode build logs and dispatches comprehensive build data to our analytics system.</p>
<h2 id="code-management" tabindex="-1" class="marketing__blog_post__body__content__heading">
Code Management<a href="#code-management" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Code Management"></a></h2>
<h4 id="which-code-architectures-and-design-patterns-are-predominant-at-glovo?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Which code architectures and design patterns are predominant at Glovo?<a href="#which-code-architectures-and-design-patterns-are-predominant-at-glovo?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Which code architectures and design patterns are predominant at Glovo?"></a></h4>
<p>
Although many teams adopt <a href="https://en.wikipedia.org/wiki/Model–view–viewmodel">MVVM</a> + Coordinators, we encourage teams to choose architectures that best fit their needs. However, some rules do apply across teams. For instance, in the Customer app, all teams utilize <a href="https://github.com/uber/needle">Needle</a> for dependency injection.</p>
<h4 id="which-platform-frameworks-are-frequently-utilized?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Which platform frameworks are frequently utilized?<a href="#which-platform-frameworks-are-frequently-utilized?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Which platform frameworks are frequently utilized?"></a></h4>
<p>
<a href="https://developer.apple.com/documentation/uikit">UIKit</a> and <a href="https://developer.apple.com/documentation/corelocation">Core Location</a> are our mainstays, with occasional use of <a href="https://developer.apple.com/documentation/coredata/">Core Data</a>.</p>
<h4 id="how-does-glovo-manage-external-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How does Glovo manage external dependencies?<a href="#how-does-glovo-manage-external-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How does Glovo manage external dependencies?"></a></h4>
<p>
Our dependencies are currently managed through <a href="https://cocoapods.org">Cocoapods</a>. However, we&#39;ve implemented a strict vetting process for adding new external dependencies. Previously, there were fewer restrictions on incorporating new external dependencies, but after examining numerous post-incident reviews, we found that many issues in production were traced back to these external sources. These not only affected production but also worsened the developer experience. For instance, significant changes in the APIs of <a href="https://github.com/Quick/Quick">Quick</a> and <a href="https://github.com/Quick/nimble">Nimble</a> meant we had to allocate substantial resources to keep our test suites up to date. We’ve finally started using <a href="https://developer.apple.com/documentation/xctest">XCTest</a> directly to streamline the process.</p>
<p>
Now, <strong>before adding a new dependency, we conduct a thorough assessment</strong>. This includes checking the code quality, gauging its impact on build time and binary size, and assessing its overall reliability. Such experiences have underscored the importance of a shift in our engineering mindset regarding external dependencies.</p>
<blockquote>
  <p>
We&#39;ve come to view anything we incorporate into our app as an extension of our own codebase because it affects both our development process and performance in production.  </p>
</blockquote>
<h2 id="processes-and-tools:-optimizing-release-cycles-and-feature-distribution" tabindex="-1" class="marketing__blog_post__body__content__heading">
Processes and Tools: Optimizing Release Cycles and Feature Distribution<a href="#processes-and-tools:-optimizing-release-cycles-and-feature-distribution" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Processes and Tools: Optimizing Release Cycles and Feature Distribution"></a></h2>
<h4 id="could-you-detail-the-release-schedule-and-feature-distribution-practices-at-glovo?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you detail the release schedule and feature distribution practices at Glovo?<a href="#could-you-detail-the-release-schedule-and-feature-distribution-practices-at-glovo?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you detail the release schedule and feature distribution practices at Glovo?"></a></h4>
<p>
We’ve streamlined our release process to be weekly which involves release branch creation,  internal beta shipping, submission for review, phased rollouts, and subsequent full releases. Our current release pipelines are built on top of <a href="https://www.jenkins.io">Jenkins</a> with <a href="https://groovy-lang.org">Groovy</a> scripting language, but we&#39;re transitioning to <a href="https://docs.github.com/en/actions">Github Actions</a>.</p>
<p>
Internal alpha builds are shipped upon every PR merge into <code class="inline">develop</code>, and <strong>beta versions are continuously shipped for 3000+ employees</strong>, ensuring regular internal testing and feedback. This strategy, coupled with incentivized employee beta usage, aids in early identification and swift rectification of potential issues.</p>
<p>
<a href="https://youtu.be/QIprGMU2S20">Here is a talk</a> that, although a bit old, goes deeper in our release process.</p>
<h4 id="how-is-the-rapid-iteration-of-new-features-ensured?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How is the rapid iteration of new features ensured?<a href="#how-is-the-rapid-iteration-of-new-features-ensured?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How is the rapid iteration of new features ensured?"></a></h4>
<p>
<strong>&quot;Building less to iterate faster&quot; encapsulates our approach.</strong> We leverage modularization and tooling to allow engineers to work with independent, module-specific example apps, minimize build times, and facilitate efficient development through precompiled dependencies. This ensures that we don’t waste time waiting for libraries to be built, minimizing not only incremental builds but also clean ones.</p>
<h4 id="how-is-the-testing-strategy-formulated-to-align-with-the-development-and-release-cycles?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How is the testing strategy formulated to align with the development and release cycles?<a href="#how-is-the-testing-strategy-formulated-to-align-with-the-development-and-release-cycles?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How is the testing strategy formulated to align with the development and release cycles?"></a></h4>
<p>
Developers typically run specific module or suite tests locally. However, CI presents the unique challenge of ensuring thorough testing while keeping a rapid feedback loop.</p>
<p>
To address this, many organizations run all test suites in their CI, but that leads to delayed feedback. In contrast, <strong>we developed an internal solution which we refer to as &#39;selective test running&#39;.</strong> This tool identifies changed modules, analyzes our dependency tree for all related modules, and then exclusively tests them. When combined with precompiling dependencies, <strong>we&#39;ve seen a 40% reduction in CI time</strong>, which is a significant boost for a modularized codebase.</p>
<p>
In addition to this, <strong>we&#39;ve automated end-to-end UI test executions against local servers providing mocked responses.</strong> This not only boosts our confidence but also allows a release cycle free from manual intervention.</p>
<h2 id="closing-thoughts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing Thoughts<a href="#closing-thoughts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing Thoughts"></a></h2>
<p>
<a href="https://glovoapp.com">Glovo</a> demonstrates a multifaceted approach to managing a large-scale development environment, striking a balance between structure and autonomy, thoroughness, and agility. Using a carefully crafted architecture and a meticulously designed development and release cycle, they manage to navigate the complexities that emerge in large-scale development settings. For organizations scaling up, adopting a similarly strategic and tool-facilitated approach to structure, development, and release processes may well pave the way for sustainable growth and development efficiency.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ The Evolution of iOS Development and the Role of Tuist ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist, born in 2017, addresses challenges in scaling Xcode projects. Despite new tools like the Swift Package Manager, the need for Tuist persists. ]]></summary>
      <link href="https://tuist.dev/blog/2023/09/23/ios-evolution-and-tuist"/>
      <id>https://tuist.dev/blog/2023/09/23/ios-evolution-and-tuist</id>
      <updated>Sat, 23 Sep 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <h1 id="tuist's-role-in-the-changing-landscape-of-ios-development" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist&#39;s Role in the Changing Landscape of iOS Development<a href="#tuist's-role-in-the-changing-landscape-of-ios-development" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist's Role in the Changing Landscape of iOS Development"></a></h1>
<p>
Tuist was conceived in 2017 to address the growing complexities of iOS development. The journey to modularize Xcode projects was about crafting a maintainable codebase accessible to multiple teams. However, <strong>using only the primitive of Xcode projects made the task daunting</strong>. We yearned for an extensible build system to tackle the challenges we encountered, but that wasn&#39;t the reality then. Fast forward to today: while the landscape has transformed with innovations like <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>, <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/">Swift Macros</a>, and various build tools — and even an official solution from Apple (<a href="https://www.swift.org/package-manager/">Swift Package Manager</a>) for Xcode project dependencies — the core challenges persist. Alarmingly, developers often harbor the hope that official tools will solve all issues, oblivious to the complications they introduce. This post aims to provide clarity on the current state, speculate on the direction Apple might have chosen, and assert why Tuist remains pertinent.</p>
<h2 id="xcode-projects:-the-beginning" tabindex="-1" class="marketing__blog_post__body__content__heading">
Xcode Projects: The Beginning<a href="#xcode-projects:-the-beginning" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Xcode Projects: The Beginning"></a></h2>
<p>
In 2003, when Apple introduced the first iteration of Xcode, projects bore little resemblance to today&#39;s structure. Often comprising just a single target for <a href="https://en.wikipedia.org/wiki/MacOS">macOS</a>, these projects were devoid of intricate dependencies and didn&#39;t facilitate code interoperability between diverse languages. Interestingly, <a href="https://en.wikipedia.org/wiki/Git">Git</a>, a now indispensable tool, wasn&#39;t even around; <a href="https://en.wikipedia.org/wiki/Linus_Torvalds">Linus Torvalds</a> introduced it in 2005. However, as the ecosystem burgeoned — spanning multiple platforms and an expanding user base — both applications and the projects underpinning them grew in complexity. Apple had to refine Xcode projects, the foundational unit that Xcode interacts with.</p>
<p>
For those unfamiliar, Xcode projects consist of smaller, pivotal components, with the <code class="inline">project.pbxproj</code> file being paramount. This PropertyList-encoded file remains concealed from the developer, with Apple envisioning all interactions through Xcode&#39;s UI. Hence, any modification in the UI corresponds to changes in the <code class="inline">project.pbxproj</code> file. Regrettably, the adoption of a static build system has often been the root cause of issues developers would later grapple with.</p>
<h2 id="the-shift:-monolithic-to-multi-project-workspaces" tabindex="-1" class="marketing__blog_post__body__content__heading">
The Shift: Monolithic to Multi-project Workspaces<a href="#the-shift:-monolithic-to-multi-project-workspaces" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The Shift: Monolithic to Multi-project Workspaces"></a></h2>
<p>
It became evident that <code class="inline">.pbxproj</code> files weren&#39;t designed for collaboration. To combat this, Apple encouraged developers to fragment their monolithic projects. The primary motivation was to reduce issues like recurring Git conflicts, inherent to a monolithic file structure. March 2011 marked a significant change with Xcode 4 introducing <a href="https://developer.apple.com/library/archive/featuredarticles/XcodeConcepts/Concept-Workspace.html"><strong>Workspaces</strong></a>. Although a promising concept on paper, its real-world application was fraught with complications. Workspaces inevitably resulted in a <strong>distributed target graph sprawled across multiple projects</strong>. Consequently, a <code class="inline">.pbxproj</code> from one project might reference a target defined in another. Git conflicts in cryptic <code class="inline">.pbxproj</code> files became a frequent developer annoyance, often leading to broken projects. In tandem, Apple launched a feature for <strong>implicit dependency detection</strong>. Although intended to aid developers, this added layer of abstraction complicated scalability. Optimizing and ensuring correctness is more straightforward with an explicit graph. Apple tried striking <strong>a balance between developer convenience and scalability but seemed to favor the former</strong>, inadvertently complicating the latter. Back then, the ramifications were limited, but the scenario has drastically changed.</p>
<blockquote>
  <p>
Apple introduced comments in <code class="inline">.pbxproj</code> files in Xcode 10 (September 2018) as part of a broader effort to improve the diffing and merging experience with version control systems, notably Git.  </p>
</blockquote>
<h2 id="code-sharing-across-xcode-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Code Sharing Across Xcode Projects<a href="#code-sharing-across-xcode-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Code Sharing Across Xcode Projects"></a></h2>
<p>
2011 was also significant for another reason: the birth of <a href="https://cocoapods.org/">CocoaPods</a>. As the broader tech community embraced package managers to nurture ecosystems, Xcode lagged. <a href="https://en.wikipedia.org/wiki/CocoaPods">Eloy Durán and Fabio Pelosin</a> tackled this challenge head-on. Due to the inextensibility of Xcode&#39;s build system, their solution comprised a blend of project generation and <code class="inline">.xcconfig</code> files. This approach integrated a new Xcode project into a workspace containing all dependencies. <strong>Given Apple&#39;s constraints, their project generation strategy was innovative</strong>. Their pioneering efforts greatly benefited the Swift and Objective-C communities and laid a foundation for tools like Tuist.</p>
<h2 id="swift-package-manager:-the-game-changer-of-2016" tabindex="-1" class="marketing__blog_post__body__content__heading">
Swift Package Manager: The Game Changer of 2016<a href="#swift-package-manager:-the-game-changer-of-2016" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Swift Package Manager: The Game Changer of 2016"></a></h2>
<p>
<strong>Five years post-CocoaPods</strong>, Apple unveiled their official package manager: <a href="https://www.swift.org/package-manager/">the Swift Package Manager (SPM)</a>. The initial response was euphoric, but <strong>it took until 2019 for Apple to integrate it into Xcode</strong>. As CocoaPods usage declined, a migration wave toward SPM began. Some even envisaged SPM as a potential project manager. The community&#39;s excitement soon manifested as tools built around SPM. However, <strong>leveraging a tool beyond its intended purpose often leads to unintended complexities.</strong></p>
<h2 id="build,-launch,-and-generation-time" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build, launch, and generation time<a href="#build,-launch,-and-generation-time" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build, launch, and generation time"></a></h2>
<p>
Until the Swift Package Manager&#39;s integration, there were two stages in development: <strong>generation and build time.</strong> Generation time occurred before opening an Xcode project. This was the workaround for Xcode&#39;s inextensible build system. Tools like <code class="inline">bundle exec pod install</code> or <code class="inline">tuist generate</code> output something ready for opening and compiling. When Apple integrated the Swift Package Manager, they introduced a new phase: <strong>launch time</strong>. This means that upon launching a project, it might not be ready for interaction.</p>
<p>
The integration, even after three years of development, had overlooked implications:</p>
<ul>
  <li>
Cleaning derived data purges resolved dependencies, making projects unusable.  </li>
  <li>
Failure in resolving dependencies creates issues due to Xcode&#39;s private usage of the Swift Package Manager.  </li>
  <li>
And more problems arise with Xcode&#39;s implicit dependency resolution and the introduction of more private integrations.  </li>
</ul>
<p>
While using the Swift Package Manager as a project manager sounds ideal, it&#39;s not feasible for large-scale apps. Many challenges can be addressed at the UI level, but the ones that surface at scale are <strong>neither addressed by Apple, neither made addressable by the community.</strong></p>
<h2 id="what-could-apple-have-done-differently?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What could Apple have done differently?<a href="#what-could-apple-have-done-differently?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What could Apple have done differently?"></a></h2>
<p>
There&#39;s no silver bullet solution for this, but <strong>Swift Package Manager could have been an excellent inflection point to start building a more extensible build system.</strong> Imagine how amazing that would have been for the community. Organizations like <a href="https://spotify.com">Spotify</a> or <a href="https://lyft.com">Lyft</a> that need a more sophisticated build system like <a href="https://bazel.build/">Bazel</a> wouldn&#39;t have to resort to project generation to integrate Bazel into Xcode. We could have used the same foundation to introduce optimizations and tools useful at scale, such as telemetry or binary caching. Even Swift Package Manager could have been developed by those who made <a href="https://cocoapods.org">CocoaPods</a> possible if the right APIs were provided. Designing tooling that targets a wide range of users is very challenging, so they could have adopted a mindset that we support 90% of the users with our default and expose APIs for developers to help with the rest. But what are they already doing with Swift Build Tools?
Kind of, but the integration between Xcode and SPM remains closed. Any communication that happens there is private and not exposed to developers.</p>
<h2 id="why-is-tuist-still-relevant?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why is Tuist still relevant?<a href="#why-is-tuist-still-relevant?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why is Tuist still relevant?"></a></h2>
<p>
Because we didn&#39;t have APIs, we had to resort to project generation. <em>Would it have been better if we had APIs?</em> Hell yeah! <em>Who wants an extra phase when everything can happen at build time?</em> But we had to resort to the same API CocoaPods used back then. This is extremely frustrating. We spend our days trying to help organizations that find themselves between &quot;I want to use the cool stuff from Apple even if I know it&#39;s not ready&quot; and &quot;I have to use Tuist, but I have to make sure you guys don&#39;t take me from the cool stuff everyone is talking about.&quot; It is sometimes frustrating, but we&#39;ll further work on the problem space as much as possible. <strong>Being able to open a project and start working on it without compiling pieces that other developers have already compiled or having data to make informed decisions is the way to work at scale</strong>, and Apple is not interested in that—at least today. So when people wonder why they should use Tuist, our common answer is if you want to remain productive and not have to deal with the issues that Apple&#39;s tooling brings, you should use Tuist.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Trendyol and Tuist: Engineering Apps at Scale ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Dive into our exclusive chat with Trendyol, Turkey's e-commerce giant. Explore how they leverage Tuist for expansive iOS development, unravel their tools, team dynamics, and the secrets to managing tech at scale. A must-read for all developers ]]></summary>
      <link href="https://tuist.dev/blog/2023/09/08/trendyol-and-tuist"/>
      <id>https://tuist.dev/blog/2023/09/08/trendyol-and-tuist</id>
      <updated>Fri, 08 Sep 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In the bustling landscape of Turkey&#39;s e-commerce, <a href="https://trendyol.com">Trendyol</a> stands as a beacon. As the nation&#39;s foremost e-commerce platform, Trendyol isn&#39;t simply about online shopping. It represents an entire digital ecosystem, a &quot;super app,&quot; dedicated to providing users with an unparalleled, diverse range of services. But, beneath this massive digital edifice, there&#39;s an intricate dance of technology, teamwork, and tools. And one tool that has been instrumental for Trendyol is Tuist. We recently sat down with the developers at Trendyol to gain insights into how they use Tuist to meet the challenges of developing apps on such a monumental scale.</p>
<h2 id="project-background-and-introduction" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project Background and Introduction<a href="#project-background-and-introduction" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project Background and Introduction"></a></h2>
<h3 id="what-is-the-size-of-your-team-and-what-is-the-structure-of-its-organization?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is the size of your team and what is the structure of its organization?<a href="#what-is-the-size-of-your-team-and-what-is-the-structure-of-its-organization?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is the size of your team and what is the structure of its organization?"></a></h3>
<p>
Our mobile team is composed of a talented and dedicated group of <strong>140 professionals who work collectively on both iOS and Android platforms</strong>. As a dynamic and innovative organization, Trendyol operates as a super app, offering a diverse range of services through various omnichannels on the platform. To ensure efficient management and specialization, each omnichannel has its own dedicated domain teams. This organizational structure enables us to effectively cater to the unique needs and demands of each omnichannel, fostering a cohesive and agile work environment.</p>
<p>
As the platform team, we provide services to five different channels and support ten distinct teams. Our primary focus is to enhance the developer experience, tooling, and performance for these teams. We consider each team as our valued client, working diligently to meet their specific needs and align with their interests in these areas.</p>
<p>
  <img src="/marketing/images/blog/2023/09/08/organization.png" alt="A diagram that shows Trendyol&#39;s team structure. The platform team supports peripheral organizations such as Turkey, International, DolapLite, Grocery, and Meal, which are focused on a specific products.">
</p>
<h2 id="project-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project architecture<a href="#project-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project architecture"></a></h2>
<h3 id="could-you-tell-us-about-your-project-architecture?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you tell us about your project architecture?<a href="#could-you-tell-us-about-your-project-architecture?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you tell us about your project architecture?"></a></h3>
<p>
We utilize the <a href="https://www.objc.io/issues/13-architecture/viper/">VIPER</a> architecture in our app, which is composed of View, Interactor, Presenter, Entity, and Router components.</p>
<p>
We chose VIPER for its strong alignment with <a href="https://en.wikipedia.org/wiki/SOLID">SOLID principles</a> and its modular design. This ensures a clean, maintainable codebase and makes unit testing more straightforward. VIPER&#39;s scalability also makes it easier to onboard new developers who can focus on specific components.</p>
<p>
On a practical level, VIPER promotes <strong>parallel development</strong>. Each developer can specialize in certain components, simplifying code reviews. While there&#39;s an initial learning curve and some boilerplate, we find these are outweighed by long-term benefits like maintainability and scalability. We even have <strong>custom Xcode templates</strong> to speed up development.</p>
<h4 id="exploring-swiftui" tabindex="-1" class="marketing__blog_post__body__content__heading">
Exploring SwiftUI<a href="#exploring-swiftui" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Exploring SwiftUI"></a></h4>
<p>
We recently shifted our deployment target to <a href="https://support.apple.com/en-us/HT211808">iOS 14</a>. This move opened up the opportunity to integrate <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a> into our project. The motivation behind this was multi-fold:</p>
<ul>
  <li>
<strong>User Experience:</strong> SwiftUI allows for smoother animations and more native components, enhancing the overall user experience.  </li>
  <li>
<strong>Developer Productivity:</strong> The declarative nature of SwiftUI simplifies UI development, allowing our developers to accomplish more with less code.  </li>
  <li>
<strong>Future-Proofing:</strong> As Apple pushes SwiftUI as the future of iOS development, adopting it early places us at an advantage in terms of maintainability and access to new features.  </li>
</ul>
<p>
As technologies continue to mature and new architectural patterns emerge, we&#39;re always open to evaluating them. Whether it&#39;s new patterns that mesh well with SwiftUI, or even entirely new paradigms, our team is excited by the potential to improve and optimize.</p>
<p>
In summary, <strong>while VIPER has served us well, our architecture is not static</strong>. It&#39;s influenced by our commitment to best practices, the evolving tech landscape, and our continual desire to deliver the best possible product.</p>
<h3 id="what-motivated-you-to-migrate-to-tuist?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What motivated you to migrate to Tuist?<a href="#what-motivated-you-to-migrate-to-tuist?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What motivated you to migrate to Tuist?"></a></h3>
<p>
Before using Tuist, we encountered the following problems:</p>
<ul>
  <li>
Committing Xcode project and workspace files to version control, which led to merge conflicts and a lack of flexibility in managing project files.  </li>
  <li>
Inconsistent manual configuration of Xcode projects, resulting in discrepancies across projects.  </li>
  <li>
Inconsistent dependency management.  </li>
  <li>
Unstable <a href="https://www.swift.org/package-manager/">Swift Package Manager (SPM)</a> resolution processes.  </li>
  <li>
Complexity in managing Xcode projects and workspaces.  </li>
  <li>
A time-consuming setup process for new modules.  </li>
  <li>
Tedious manual steps required for project configuration and setup.  </li>
</ul>
<p>
By adopting Tuist, we effectively tackled numerous challenges within our development process.</p>
<h3 id="how-do-you-use-tuist-today?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you use Tuist today?<a href="#how-do-you-use-tuist-today?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you use Tuist today?"></a></h3>
<p>
We have fully integrated Tuist into our development workflow, and the impact has been transformative. Tuist has enabled us to eliminate the need to commit Xcode project and workspace files to version control by utilizing its runtime generation capabilities. This has not only <strong>mitigated the risk of merge conflicts</strong> but also provided us with <strong>greater flexibility in managing project files.</strong></p>
<p>
Moreover, Tuist has played a crucial role in <strong>ensuring consistency across projects</strong> by eliminating the manual configuration of Xcode projects. Its streamlined and intuitive approach to configuration has enabled us to effortlessly <strong>enforce best practices and maintain uniformity throughout our codebase.</strong></p>
<p>
Additionally, Tuist has simplified the management of Xcode projects and workspaces, significantly <strong>reducing complexity</strong>. This has allowed us to focus more on development, sparing us the intricacies of project setup tasks.</p>
<p>
One of the most valuable features of Tuist has been its <strong>templates</strong>, which have boosted our productivity. With Tuist&#39;s templates, we can swiftly establish new modules with standardized structures and configurations, saving considerable time and effort.</p>
<p>
Furthermore, our overall developer experience has improved significantly as Tuist minimized the number of manual steps required for project configuration and setup. Its efficient and automated processes have <strong>streamlined our workflow, empowering us to concentrate on coding and enhancing productivity.</strong></p>
<p>
In summary, Tuist has been instrumental in addressing the challenges we previously faced in Xcode project management, dependency handling, consistency, productivity, and developer experience. Its seamless integration into our development process has revolutionized our project execution, leading to smoother and more efficient development.</p>
<h3 id="how-do-you-use-tuist-templates?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you use Tuist templates?<a href="#how-do-you-use-tuist-templates?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you use Tuist templates?"></a></h3>
<p>
We have integrated the use of <a href="https://docs.old.tuist.io/commands/scaffold/">templates</a> to <strong>optimize our development process</strong>. A particularly noteworthy template that we employ is engineered to <strong>generate new modules.</strong> This template facilitates the creation of a new Xcode project with customizable parameters, such as its name and path. The resulting project is automatically configured with essential targets, including Interface, Implementation, Test Support, and Tests. This efficient method not only accelerates the initiation of new modules but also guarantees consistency across our projects. It is an invaluable instrument that harmonizes with our development practices and aids us in upholding a superior standard of code quality.</p>
<h2 id="build-times" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build times<a href="#build-times" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build times"></a></h2>
<h3 id="how-long-do-clean-and-incremental-builds-take?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How long do clean and incremental builds take?<a href="#how-long-do-clean-and-incremental-builds-take?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How long do clean and incremental builds take?"></a></h3>
<p>
The clean build process takes approximately 295 seconds, whereas the <strong>incremental build takes around 40 seconds.</strong> We are managing a substantial total of <strong>230 .xcodeproj modules</strong> within our project.</p>
<p>
The clean build involves recompiling the entire project from scratch, which accounts for the longer duration, whereas the incremental build only compiles the modified or newly added files, resulting in a significantly faster build time.</p>
<p>
Given the large number of modules, we have <strong>managed to optimize our build times considerably by utilizing incremental builds</strong>. This enhancement in build efficiency has had a positive impact on our development workflow, enabling us to devote more time to coding and reducing turnaround time during development iterations.</p>
<h3 id="how-do-you-ensure-incremental-builds-work-reliably?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you ensure incremental builds work reliably?<a href="#how-do-you-ensure-incremental-builds-work-reliably?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you ensure incremental builds work reliably?"></a></h3>
<p>
We <a href="https://medium.com/trendyol-tech/revamping-trendyols-ios-app-a-modularization-success-story-a6c1d2c4188b">segregated</a> concrete modules from <strong>interface modules</strong>, enabling us to maximize the benefits of incremental building. In this setup, we employ our own dependency container. Concrete modules are not directly interconnected; rather, interface modules serve as intermediaries between them. Consequently, Xcode only compiles the modified sections, thereby minimizing our build time.</p>
<h3 id="what’s-your-release-cadence-and-what-does-the-process-look-like?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your release cadence and what does the process look like?<a href="#what’s-your-release-cadence-and-what-does-the-process-look-like?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your release cadence and what does the process look like?"></a></h3>
<p>
We follow a structured release cadence to guarantee the prompt delivery of packages. Our release cycle is bi-weekly, with predetermined release dates set for each cycle. In preparation for these releases, we initiate the process by creating a <a href="https://en.wikipedia.org/wiki/Software_release_life_cycle#Release_candidate">Release Candidate (RC)</a> branch a few days before the scheduled release date.</p>
<p>
The RC branch functions as a dedicated space for finalizing the upcoming release. Once the RC branch is established, our <a href="https://en.wikipedia.org/wiki/Quality_assurance">Quality Assurance (QA)</a> team takes the helm and begins <a href="https://en.wikipedia.org/wiki/Regression_testing">regression testing</a>. This rigorous testing phase enables us to comprehensively evaluate the stability and functionality of the package before its live deployment.</p>
<p>
Adhering to this approach allows us to confidently ensure the reliability of our releases and <strong>minimize the risk of unexpected issues arising</strong>. Our well-defined release cadence, complemented by the proactive creation of the RC branch and thorough QA regression tests, empowers us to consistently achieve our bi-weekly release targets while upholding a high standard of software quality.</p>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
Our <a href="https://medium.com/trendyol-tech/managing-ios-tests-on-scale-a-symphony-a644275d0bbc">testing strategy</a> encompasses various types of tests, executed intentionally in different scenarios and, when necessary, capable of blocking pipelines. To discuss this quantitatively:</p>
<p>
We have over <strong>25k Unit, 1.5k Regression, 250 Smoke Tests, and 500 Snapshots</strong>. Both smoke and unit tests are executed on every commit and act as blockers on merge requests.</p>
<p>
<a href="https://en.wikipedia.org/wiki/Unit_testing"><strong>Unit Tests</strong></a> are indispensable. For many years, it has been mandatory to write and maintain tests for all developments. Recently, we have been using tools (explained in the tools section) that automatically generate these tests, speeding up the process. However, it is crucial to maintain a balance between automation and manual effort to prevent the tests from being neglected, much like unread documents. We continuously fine-tune this balance.</p>
<p>
Our <strong>UI Testing framework</strong>, built on <a href="https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/09-ui_testing.html">XCUITest</a>, is highly advanced. A significant portion of the code is auto-generated by our internal code generators. Our internal mock server allows us to easily mock the desired services. <a href="https://medium.com/trendyol-tech/how-to-make-ios-ui-testing-fast-and-reliable-6f572a0955f2">This setup</a> simplifies the process of writing smoke tests for basic flows during development.</p>
<p>
<a href="https://en.wikipedia.org/wiki/Smoke_testing_(software)"><strong>Smoke Tests</strong></a> were initially written to ensure that every page and element worked flawlessly before writing complex regression tests in the production environment. Another purpose was to confirm that the UI test infrastructure wasn&#39;t broken by the developments, by adding these tests as a merge check at an early stage. We quickly achieved close to 100% coverage, and it is now a must to add these tests when new pages are written.</p>
<p>
<a href="https://en.wikipedia.org/wiki/Regression_testing"><strong>Regression Tests</strong></a> operate in the production environment using real test data and leverage the same architecture created for our smoke tests. These tests ensure existing functionality remains untouched with new updates. This approach not only assures quality but also accelerates our release cycle.</p>
<p>
We use <strong>Snapshot Tests</strong> differently from many teams. Instead of using a unit test style, <a href="https://medium.com/trendyol-tech/automated-visual-testing-with-snapshots-part-1-ee9c5cf58cca">we use our existing UI Test framework</a> to handle actions and flows while we use the <a href="https://github.com/pointfreeco/swift-snapshot-testing">swift-snapshot-testing</a> library to take and compare the screenshots. Architectural reasons and considerations around maintenance responsibilities led us to choose this path. We see it as a low-maintenance tool that effectively catches many bugs, and we share all test results via buttons on Slack.</p>
<p>
Lastly, we also have a small number of <a href="https://en.wikipedia.org/wiki/Integration_testing"><strong>Integration tests</strong></a> written for our in-house SDK(s). End-to-end testing of certain systems, such as events, can be quite difficult and challenging. In this context, these tests grant us a significant amount of confidence in our systems.</p>
<h3 id="have-you-developed-any-in-house-tool?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Have you developed any in-house tool?<a href="#have-you-developed-any-in-house-tool?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Have you developed any in-house tool?"></a></h3>
<p>
In our pursuit to streamline our development processes and address the unique challenges we face at Trendyol, we&#39;ve invested time and effort in developing several in-house tools. These tools are designed to cater to our specific needs, and have significantly contributed to our efficiency and productivity in developing iOS apps at scale. Here is a list of some of the in-house tools we have developed:</p>
<h4 id="mockolo" tabindex="-1" class="marketing__blog_post__body__content__heading">
Mockolo<a href="#mockolo" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Mockolo"></a></h4>
<p>
Mockolo is a powerful tool that generates all the necessary mocks for a protocol, conforming to it with just a single button press. It goes a step further by supporting the new async-await structure. Developed on top of <a href="https://github.com/uber/mockolo">Uber&#39;s Mockolo library</a>, it has been tailored to fit the team&#39;s needs and optimized for SwiftKit. The mock output has been fine-tuned to align seamlessly with the project requirements, making it an invaluable asset for the team&#39;s testing and development processes. With Mockolo, generating mocks and staying up-to-date with new Swift features has never been easier.</p>
<h4 id="latiflex" tabindex="-1" class="marketing__blog_post__body__content__heading">
LatiFlex<a href="#latiflex" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to LatiFlex"></a></h4>
<p>
LatiFlex is an efficient <strong>in-app debugging tool</strong> designed to streamline our debugging process. With its powerful features, we can easily track network requests, search in network responses, copy Curl commands and responses, monitor analytic events, search events, copy event parameters, execute deeplinks within our application, and seamlessly switch between different environments. LatiFlex simplifies debugging, making it faster and more effective.</p>
<h4 id="mockserver" tabindex="-1" class="marketing__blog_post__body__content__heading">
MockServer<a href="#mockserver" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to MockServer"></a></h4>
<p>
MockServer is a powerful <strong>request mocking tool</strong> that offers flexibility and ease of use. With its user-friendly features, you can effortlessly save and update requests for future use. The tool provides various filtering options such as location (all, path, query, scenario, method, status) to customize your mocking experience. Additionally, you can conveniently list all mocking requests and apply search filters to find specific requests efficiently. MockServer is your go-to solution for seamless and hassle-free request mocking.</p>
<h4>
<a href="https://gitlab.com">GitLab</a> Menu Bar</h4>
<p>
GitLab Menu Bar is a handy and <strong>feature-rich menubar application designed for an optimized GitLab experience</strong>. The application lists merge requests with the user&#39;s approval count, build status, and conflict mark. It also displays merge requests that need to be reviewed, providing date and approval status for easy sorting. The &quot;Create MR&quot; button generates merge requests based on the user&#39;s recently pushed branches. In case of a failed pipeline, the app offers the option to trigger the pipeline again. Additionally, users can switch between branches and create new ones using the macOS Shortcuts app integration. Conflicted files can be opened with Visual Studio Code using the macOS Shortcuts app. The application streamlines the process of sending export IPA requests. For the mobile team, the QA Mode showcases automation tool export options and task status, requiring the board ID. GitLab Menu Bar aims to provide users with convenience and productivity, empowering them to enhance their GitLab workflow. When the user presses the merge button, a confirmation dialog appears, prompting the user to review his actions before proceeding. Creating a new merge request becomes effortless as GitLab automatically formats the merge request name and description for the user. Additionally, the branch name is automatically set as the merge request name, ensuring consistency in identification. For a comprehensive overview, all commit messages are aggregated and set as the merge request description.</p>
<h4 id="dependency-analyzer" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependency Analyzer<a href="#dependency-analyzer" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependency Analyzer"></a></h4>
<p>
A Tuist plugin that analyzes explicit dependencies between modules by using SwiftSyntax.</p>
<h4 id="switytestgenerator" tabindex="-1" class="marketing__blog_post__body__content__heading">
SwityTestGenerator<a href="#switytestgenerator" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to SwityTestGenerator"></a></h4>
<p>
We developed a tool called <a href="https://github.com/aytugsevgi/SwityTestGenerator">SwityTestGenerator</a> to <strong>simplify the process of writing UI tests</strong>, which previously required setting accessibility identifiers for each <code class="inline">IBOutlet</code> individually. This process was repetitive and manual. With SwiftyTestGenerator, we can easily create the necessary elements for UI testing and have made it available for use by all team members.</p>
<h2 id="collaboration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Collaboration<a href="#collaboration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Collaboration"></a></h2>
<h3 id="can-you-discuss-a-bit-about-the-collaboration-between-different-roles-(such-as-developers,-designers,-and-product-managers)-in-your-team?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Can you discuss a bit about the collaboration between different roles (such as developers, designers, and product managers) in your team?<a href="#can-you-discuss-a-bit-about-the-collaboration-between-different-roles-(such-as-developers,-designers,-and-product-managers)-in-your-team?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Can you discuss a bit about the collaboration between different roles (such as developers, designers, and product managers) in your team?"></a></h3>
<p>
Collaboration is a cornerstone of our team’s success, and we have established a well-defined process to ensure <strong>seamless communication and coordination among various roles</strong>, including developers, designers, and product managers.</p>
<ul>
  <li>
<strong>Regular Cross-Functional Meetings:</strong> We hold regular cross-functional meetings, such as sprint planning sessions, stand-ups, and retrospectives. These meetings bring together developers, designers, and product managers to discuss project progress, upcoming features, design considerations, and any potential challenges. This facilitates a shared understanding of goals, timelines, and priorities.  </li>
  <li>
<strong>Early Involvement in Design:</strong> Designers are an integral part of our development process right from the start. They collaborate closely with product managers and developers to define user stories, user flows, and design mockups. This ensures that design considerations are incorporated early, minimizing potential design-related roadblocks down the line.  </li>
  <li>
<strong>Collaborative Design Reviews:</strong> Design reviews involve developers, designers, and product managers, where we collectively assess and provide feedback on design mockups and prototypes. This iterative process allows us to align on the visual and functional aspects of the product and make necessary adjustments before development begins.  </li>
  <li>
<strong>Feature Specification Workshops:</strong> Developers and product managers collaborate on detailed feature specification workshops. These sessions involve in-depth discussions about the technical requirements, user stories, acceptance criteria, and potential challenges. This collaborative effort ensures that the development team has a comprehensive understanding of the desired outcomes.  </li>
  <li>
<strong>Continuous Communication:</strong> We maintain open lines of communication through various channels, such as messaging platforms and project management tools. This enables quick exchanges of information, updates on progress, and the ability to address questions or concerns in real-time.  </li>
  <li>
<strong>User Acceptance Testing (UAT):</strong> Product managers and developers work closely during the UAT phase, where the product is tested by stakeholders and users. Feedback from UAT is carefully considered, and any necessary adjustments are made to ensure the final product meets the desired quality and functionality.  </li>
  <li>
<strong>Retrospectives and Feedback Loops:</strong> Regular retrospectives provide a space for all team members to reflect on the development process, share insights, and suggest improvements. This fosters a culture of continuous improvement and empowers everyone to contribute to the team’s success.  </li>
</ul>
<p>
By nurturing a collaborative environment and involving different roles throughout the development lifecycle, we are able to leverage the unique perspectives and expertise of each team member. This holistic approach results in more well-rounded and user-centric solutions, as well as a stronger sense of ownership and shared accomplishment among our team members.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
We hope this insight into Trendyol&#39;s engineering practices for developing iOS apps at scale has been enlightening. Their adept use of Tuist, among other powerful tools and collaborative practices, not only streamlines their development process but also ensures high code quality and consistency across projects. By fostering a collaborative environment, maintaining open lines of communication, and implementing comprehensive testing strategies, the <strong>Trendyol team successfully navigates the challenges associated with managing a large number of modules and delivering reliable, user-centric solutions.</strong></p>
<p>
We would like to express our gratitude to the engineers at Trendyol for sharing their valuable experiences and strategies. <strong>Their commitment to continuous improvement and innovation is truly inspiring.</strong> We believe that sharing knowledge and best practices like this contributes to the growth and success of the broader developer community.</p>
<p>
Thank you for reading, and we hope you found this interview as informative and inspiring as we did. If you are interested in learning more about Tuist and how it can help streamline your development process, please visit <a href="https://tuist.io">our website</a> or check out <a href="https://docs.old.tuist.io">our documentation</a> for more details.</p>
<p>
For more insights into engineering practices and technical articles, be sure to visit <a href="https://medium.com/trendyol-tech">Trendyol Tech&#39;s Medium blog</a> and our <a href="https://medium.com/trendyol-tech/revamping-trendyols-ios-app-a-modularization-success-story-a6c1d2c4188b">additional resources.</a></p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ XCBeautify: Supporting GitHub Actions Annotations ]]></title>
      
      
      <author>
        <name><![CDATA[ Charles Pisciotta ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn about the latest xcbeautify renderer. ]]></summary>
      <link href="https://tuist.dev/blog/2023/09/06/xcbeautify-github-actions"/>
      <id>https://tuist.dev/blog/2023/09/06/xcbeautify-github-actions</id>
      <updated>Wed, 06 Sep 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <h1 id="overview" tabindex="-1" class="marketing__blog_post__body__content__heading">
Overview<a href="#overview" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Overview"></a></h1>
<p>
<a href="https://github.com/tuist/xcbeautify">XCBeautify</a> now features an output format option for GitHub Actions.</p>
<h1 id="getting-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting Started<a href="#getting-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting Started"></a></h1>
<p>
To utilize this function, simply run <code class="inline">xcbeautify</code> and add the <code class="inline">--renderer github-actions</code> flag during execution.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
xcodebuild [flags] | xcbeautify --renderer github-actions    </shiki-highlight>
  </div>
</div>
<h1 id="how-it-works" tabindex="-1" class="marketing__blog_post__body__content__heading">
How It Works<a href="#how-it-works" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How It Works"></a></h1>
<p>
When you use the GitHub Actions renderer, xcbeautify formats output that harnesses <a href="https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions">workflow commands</a> to highlight warnings, errors, and other results directly within the GitHub user interface.</p>
<p>
When you run a pull request check with the GitHub Actions renderer, you&#39;ll find all xcodebuild results and feedback in the <code class="inline">Annotations</code> section of the run summary.</p>
<p>
  <img src="/marketing/images/blog/2023/09/06/xcbeautify-gh-summary.png" alt="An image that shows a GitHub Actions run summary with xcbeautify comments.">
</p>
<p>
Furthermore, you&#39;ll find native inline feedback on PRs. This includes compiler warnings, compiler errors, and test failures.</p>
<p>
  <img src="/marketing/images/blog/2023/09/06/xcbeautify-gh-comment.png" alt="An image that shows a GitHub Actions run with an inline xcbeautify comment.">
</p>
<p>
By using this feature, you may avoid the need for additional third-party tools, such as <a href="https://github.com/danger/swift">Danger</a> and related dependencies, to report a summary of xcodebuild output.</p>
<h1 id="introducing-renderers" tabindex="-1" class="marketing__blog_post__body__content__heading">
Introducing Renderers<a href="#introducing-renderers" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Introducing Renderers"></a></h1>
<p>
As of <a href="https://github.com/tuist/xcbeautify/releases/tag/0.21.0">0.21.0</a>, xcbeautify adds the <code class="inline">Renderer</code> concept. <code class="inline">Renderer</code> specifies the way you want xcbeautify to format its output.</p>
<p>
Historically, xcbeautify has only supported one command line output format. This is now the format provided by the <code class="inline">TerminalRenderer</code>, and it&#39;s the default option.</p>
<p>
<code class="inline">Renderer</code> provides the groundwork to add other output formats, such as for other CI/CD providers.</p>
<h1 id="final-thoughts" tabindex="-1" class="marketing__blog_post__body__content__heading">
Final Thoughts<a href="#final-thoughts" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Final Thoughts"></a></h1>
<p>
If you&#39;d like to learn more about this change, you can find the introductory pull request <a href="https://github.com/tuist/xcbeautify/pull/107">here</a>.</p>
<p>
Thank you to <a href="https://eliperkins.com">Eli Perkins</a> for providing support and direction on this change and supporting GitHub Actions annotations.</p>
<h1 id="feedback" tabindex="-1" class="marketing__blog_post__body__content__heading">
Feedback<a href="#feedback" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Feedback"></a></h1>
<p>
If you&#39;d like to provide feedback or a contribution, please consider opening an <a href="https://github.com/tuist/xcbeautify/issues">issue</a> or <a href="https://github.com/tuist/xcbeautify/pulls">pull request</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Charting Our Course: A Bold New Direction for Tuist in the Second Half of 2023 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist's vision for 2023: improved reliability, transparent processes, and reinvented collaboration. ]]></summary>
      <link href="https://tuist.dev/blog/2023/07/26/2023-tuist-direction"/>
      <id>https://tuist.dev/blog/2023/07/26/2023-tuist-direction</id>
      <updated>Wed, 26 Jul 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
The world of Tuist is growing more vibrant each day, with our repository bustling with issues and pull requests from developers worldwide. As our community has expanded, we&#39;ve faced the exciting challenge of trying to balance a multitude of tasks, all while maintaining our vision&#39;s clarity and purpose. Well, we&#39;re not just about making tools here at Tuist; we&#39;re about making dreams come true. And to do that, we need a clear, actionable plan for the future—a roadmap for our journey through the rest of 2023. So, buckle up and get ready for the thrilling ride ahead!</p>
<h2 id="reliability---our-north-star" tabindex="-1" class="marketing__blog_post__body__content__heading">
Reliability - Our North Star<a href="#reliability---our-north-star" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Reliability - Our North Star"></a></h2>
<p>
At the core of Tuist&#39;s ethos is a dedication to addressing developers&#39; scenarios in a reliable, efficient way. We&#39;re cognizant that we have fallen short of this promise recently and are ready to make a swift turnaround. From hacking around the tool to support unique scenarios to providing seamless support for Xcode project features, we&#39;re geared up to <strong>make Tuist the reliable partner you deserve.</strong></p>
<p>
From ensuring support for <strong>multi-platform targets</strong> to providing interfaces for every feature that graces the Xcode stage, we&#39;re focused on expanding our repertoire while guiding our users to contribute themselves. Not only will we improve support for existing Xcode features, but we will also introduce <strong>post-generation hooks</strong> to make your Tuist experience even more rewarding.</p>
<h3 id="embracing-dependencies-with-open-arms" tabindex="-1" class="marketing__blog_post__body__content__heading">
Embracing Dependencies with Open Arms<a href="#embracing-dependencies-with-open-arms" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Embracing Dependencies with Open Arms"></a></h3>
<p>
Our approach to dependencies using <a href="https://docs.old.tuist.io/guides/third-party-dependencies">Dependencies.swift</a> has proven useful, but we understand some users are experiencing hiccups with package integration. We&#39;re committed to ironing out these kinks, ensuring that your integration process is as smooth as Xcode&#39;s via the SPM.</p>
<p>
Moreover, we&#39;re striving to stay in sync with <a href="https://www.swift.org/package-manager/">SPM</a> and Apple&#39;s direction, allowing us to continuously improve your experience, even as the landscape evolves. We&#39;re up for the challenge—bring on the tricks, and we&#39;ll deliver the treats!</p>
<h3 id="revitalizing-caching-and-cherishing-build-and-test" tabindex="-1" class="marketing__blog_post__body__content__heading">
Revitalizing Caching and Cherishing Build and Test<a href="#revitalizing-caching-and-cherishing-build-and-test" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Revitalizing Caching and Cherishing Build and Test"></a></h3>
<p>
<a href="https://docs.old.tuist.io/building-at-scale/caching">Caching</a> isn&#39;t just a feature; it&#39;s the heart of Tuist&#39;s appeal. We&#39;re dedicated to making this process more intuitive, from introducing tools for easier debugging to providing APIs for environment information declaration. Moreover, we&#39;re committed to enhancing our build and test workflows, ensuring they&#39;re efficient and provide insights that lead to better decision-making.</p>
<Tweet id="https://twitter.com/tokarevnotes/status/1681664035861807105">
</Tweet>
<h2 id="transparency-–-the-clear-sky-of-our-journey" tabindex="-1" class="marketing__blog_post__body__content__heading">
Transparency – The Clear Sky of our Journey<a href="#transparency-–-the-clear-sky-of-our-journey" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Transparency – The Clear Sky of our Journey"></a></h2>
<p>
We&#39;re donning the cape of transparency, allowing our users a sneak peek into the tool&#39;s trajectory and our work priorities. Our vision and roadmaps will be shared regularly on our blog for feedback, and we&#39;ll adhere to a fixed release schedule and use GitHub milestones for better planning.</p>
<h2 id="sustainability-–-the-lifeline-of-tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Sustainability – The Lifeline of Tuist<a href="#sustainability-–-the-lifeline-of-tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Sustainability – The Lifeline of Tuist"></a></h2>
<p>
To ensure Tuist&#39;s longevity, we&#39;re ready to balance trimming down features with introducing a paid service for full-time project dedication. However, we want this to be a win-win situation, allowing us to support our invaluable users while avoiding unnecessary feature bloat.</p>
<h3 id="empowering-autonomy" tabindex="-1" class="marketing__blog_post__body__content__heading">
Empowering Autonomy<a href="#empowering-autonomy" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Empowering Autonomy"></a></h3>
<p>
Your independence is our victory. We&#39;re working tirelessly to remove barriers that may slow you down. From eliminating dependencies on <a href="https://github.com/tuist/tuist/blob/main/Gemfile">Ruby</a> to integrating tools like <a href="https://github.com/realm/SwiftLint">SwiftLint</a> and <a href="https://github.com/nicklockwood/SwiftFormat">SwiftFormat</a>, we&#39;re setting the stage for a smoother development experience. We&#39;re also revamping our <a href="https://docs.old.tuist.io">documentation</a> and introducing nightly releases to keep you at the forefront of Tuist&#39;s evolution.</p>
<h3 id="tuist-cloud:-reinventing-collaboration" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist Cloud: Reinventing Collaboration<a href="#tuist-cloud:-reinventing-collaboration" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist Cloud: Reinventing Collaboration"></a></h3>
<p>
Last, but not least, we&#39;re making a significant push towards rewriting <a href="https://docs.old.tuist.io/cloud/get-started">Tuist Cloud</a> with added functionalities for improved collaboration and decision-making. We&#39;ll also allow organizations to host Tuist Cloud on their servers, and we might even open-source the revamped tool! <em>(Psst, we&#39;re already on the move with this project—so get ready for a mid-summer surprise!)</em></p>
<p>
In summary, our vision for the remainder of 2023 is to do less, but better—to <strong>return to our roots and reassess our decisions in the name of sustainability</strong>. We&#39;re ecstatic about the growth in our user base, but we know it&#39;s time to ensure we&#39;re built to last. So, join us on this incredible journey, because we&#39;re not just about making your Xcode projects easier—we&#39;re about making dreams come true. Together, we can chart a course through the world of coding that&#39;s as exciting as it is rewarding.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Bundling Javascript in Swift projects using ESBuild ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ SwiftyESBuild: Streamlining Swift Web Bundling and JavaScript Integration for Effortless Development. ]]></summary>
      <link href="https://tuist.dev/blog/2023/06/23/introducing-swiftyesbuild"/>
      <id>https://tuist.dev/blog/2023/06/23/introducing-swiftyesbuild</id>
      <updated>Fri, 23 Jun 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In an ongoing effort to streamline the process of building web apps and sites with Swift, I am delighted to introduce a new Swift Package: <a href="https://github.com/pepicrft/SwiftyESBuild"><strong>SwiftyESBuild</strong></a>. While modern browsers are capable of resolving and downloading <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">ES module graphs</a>, many projects still resort to bundling for various reasons, such as optimizing loading speed and supporting modern JavaScript features that may not be compatible with certain browsers. Nowadays, there is an abundance of tools available to assist with this task, but one tool, in particular, has gained significant popularity and serves as a foundational block for other tools like <a href="https://vitejs.dev">Vite</a>, <a href="https://esbuild.github.io">ESBuild</a>.</p>
<p>
Communities like JavaScript&#39;s or Ruby&#39;s have already discovered a seamless installation path (e.g. <a href="https://github.com/rails/jsbundling-rails">jsbundling-rails</a>) that doesn&#39;t require the installation of additional runtimes like Node. Unfortunately, the Swift community lacks a similar streamlined method to integrate it into projects powered by frameworks like <a href="https://vapor.codes">Vapor</a> or <a href="https://github.com/JohnSundell/Publish">Publish</a>. This is where SwiftyESBuild comes in. By adding SwiftyESBuild as a dependency through a Swift Package, you can effortlessly incorporate the tool into your project. With just a few lines of code, you can use it to generate production-ready artifacts or keep it running in the background, automatically monitoring for any file changes.</p>
<h2 id="getting-started" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting started<a href="#getting-started" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting started"></a></h2>
<p>
To get started with <code class="inline">SwiftyESBuild</code>, all you have to do is add the dependency to your project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
.package(url: &quot;https://github.com/tuist/SwiftyESBuild.git&quot;, .upToNextMinor(from: &quot;0.1.0&quot;))    </shiki-highlight>
  </div>
</div>
<p>
After adding the dependency, you&#39;ll need to create an instance of <code class="inline">SwiftyESBuild</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let esbuild = SwiftyESBuild(version: .latest)    </shiki-highlight>
  </div>
</div>
<p>
If you don&#39;t pass any arguments, it defaults to the latest version in the system&#39;s default temporary directory. If you&#39;re working in a team, we recommend fixing the version to minimize non-determinism across environments.</p>
<h2 id="running-esbuild" tabindex="-1" class="marketing__blog_post__body__content__heading">
Running ESBuild<a href="#running-esbuild" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Running ESBuild"></a></h2>
<p>
Running ESBuild is as easy as invoking the <code class="inline">run</code> function on the <code class="inline">esbuild</code> instance, passing the options you want to use:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import TSCBasic // AbsolutePath

let entryPointPath = AbsolutePath(validating: &quot;/project/index.js&quot;)
let outputBundlePath = AbsolutePath(validating: &quot;/projects/build/index.js&quot;)
try await esbuild.run(entryPoint: entryPointPath, options: .bundle, .outfile(outputBundlePath))    </shiki-highlight>
  </div>
</div>
<p>
Check out <a href="https://github.com/tuist/SwiftyESBuild/blob/main/Sources/SwiftyESBuild/SwiftyESBuild.swift"><code class="inline">SwiftyESBuild.RunOption</code></a> to know the available options. Note that not all the options supported by ESBuild are available, which is why we&#39;ve added an <code class="inline">.arguments</code> option that allows you to pass any argument to the ESBuild CLI.</p>
<h2 id="next-steps" tabindex="-1" class="marketing__blog_post__body__content__heading">
Next steps<a href="#next-steps" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Next steps"></a></h2>
<p>
We&#39;ll add some examples for how to use the tool with frameworks like <a href="https://vapor.codes">Vapor</a> and <a href="https://github.com/JohnSundell/Publish">Publish</a>. Additionally, we plan to build a Swift Package to integrate <a href="https://orogene.dev">Orogene</a> into Swift projects. This will allow developers to resolve and pull NPM packages without having to install Node in their system. It&#39;s the last missing step to have a fully integrated JavaScript bundling experience in Swift projects without requiring Node installation.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Issue and feature bounties ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Announcing new bounty program for our Tuist contributors ]]></summary>
      <link href="https://tuist.dev/blog/2023/01/18/issue-bounties"/>
      <id>https://tuist.dev/blog/2023/01/18/issue-bounties</id>
      <updated>Wed, 18 Jan 2023 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Financing open source projects is <em>hard</em>. Therefore, we value every dollar you send our way to keep this project going after many years now. But we also want to ensure that the money is used to move the project further. This is why we&#39;re introducing <strong>issue bounties</strong>. But first:</p>
<h2 id="thank-you!" tabindex="-1" class="marketing__blog_post__body__content__heading">
Thank you!<a href="#thank-you!" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Thank you!"></a></h2>
<p>
I&#39;d like to call out all of our current public sponsors, you deserve a round of applause 👏:</p>
<ul>
  <li>
Our silver sponsor <a href="https://github.com/GetStream">@GetStream</a>  </li>
  <li>
<a href="https://github.com/csjones">@csjones</a>  </li>
  <li>
<a href="https://github.com/GlebRadchenko">@GlebRadchenko</a>  </li>
  <li>
<a href="https://github.com/SD10">@SD10</a>  </li>
  <li>
<a href="https://github.com/mflknr">@mflknr</a>  </li>
  <li>
<a href="https://github.com/shgew">@shgew</a>  </li>
</ul>
<p>
But we value as much all the past financial contributors and anybody who spent their free or company time on the project, helping others with questions, features, or issues 💜</p>
<h2 id="announcing-bounty-system" tabindex="-1" class="marketing__blog_post__body__content__heading">
Announcing bounty system<a href="#announcing-bounty-system" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Announcing bounty system"></a></h2>
<p>
Our budget is no secret and you can see <a href="https://opencollective.com/tuistapp#category-BUDGET">our expenses at Open Collective</a>. We have recently been able to cut down our monthly recurring bills which left us wondering how we can best use the financial contributions. We value the free time contributors are putting into tuist and so we want to reward them.</p>
<p>
We will experiment with a <strong>bounty system</strong> – our Tuist Core team will select issues and assign rewards to them. You will find the list <a href="https://github.com/tuist/tuist/discussions/4982">here</a>. We will regularly update the list and you are free to add your suggestions there. If you have yourself an issue you&#39;d like to see resolved, you can send a donation to our project and we will declare a bounty for you.</p>
<p>
If you are a contributor and you are interested in getting one of the bounties, just declare in a given issue you plan to work on it, implement it, and we&#39;ll send you the bounty via GitHub Sponsors or OpenCollective 🎉</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Releasing Tuist 3.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Highlighting updates from the 3.0 release and first Tuist Cloud preview. ]]></summary>
      <link href="https://tuist.dev/blog/2022/03/28/tuist-30"/>
      <id>https://tuist.dev/blog/2022/03/28/tuist-30</id>
      <updated>Mon, 28 Mar 2022 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
October of last year, we have published the last major version 2.0. Since then we have made great progress, especially with <strong>plugins, Tuist Cloud, and Dependencies.swift</strong>. We have also taken the opportunity to refine our API to be simpler to use - which meant making some breaking changes. We have detailed them all <a href="https://github.com/tuist/tuist/releases/tag/3.0.0">here</a>, along with migration steps and motivation for <em>why</em> we have done them.</p>
<p>
Below, I&#39;d like to get deeper into the new features and improvements and briefly touch on the future direction of the project.</p>
<h2 id="plugins" tabindex="-1" class="marketing__blog_post__body__content__heading">
Plugins<a href="#plugins" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Plugins"></a></h2>
<p>
<a href="https://docs.old.tuist.io/plugins/using-plugins/">Plugins</a> allow us to make Tuist an extensible platform. This approach is beneficial to both the users and tuist maintainers. For users, it means they can build <strong>plugins that suit their concrete problem</strong>. The problem might not be general enough for it to be a part of tuist itself or you want to codify your own conventions on top of what tuist offers. Plugins also make tuist easier to maintain because we can provide certain convenience features outside the main repository. The project also becomes leaner and keeps the users in charge of decisions that are outside of tuist&#39;s purview.</p>
<p>
Plugins have been in tuist for some time now but it is now possible to use <strong>third-party dependencies in plugin <a href="https://docs.old.tuist.io/plugins/creating-plugins/#tasks">tasks</a></strong>. This unlocks a lot of possibilities. And when users define a task in their <code class="inline">Config.swift</code>, it&#39;s integrated right inside the tuist CLI. For example, we have created a <a href="https://github.com/tuist/tuist-plugin-lint">new tuist plugin</a> for linting source code where we have integrated the SwiftLint package to actually do the linting. When you integrate the plugin in your project, you can just run <code class="inline">tuist lint</code> and it will trigger that plugin 🤯  How <em>cool</em> is that?</p>
<p>
But there&#39;s more. <code class="inline">tuist lint</code> also needs to know which files it should lint. For such a use-case, you can now use a completely new framework called <a href="https://docs.old.tuist.io/guides/task/#projectautomation">ProjectAutomation</a>. This framework gives <strong>tasks access to the graph</strong> and a plugin like <code class="inline">tuist lint</code> can now query the list of sources:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectAutomation
let allSources = Tuist.XcodeGraph().projects.values.flatMap(\.targets).map(\.sources)    </shiki-highlight>
  </div>
</div>
<p>
Having an access to the graph is extremely powerful and can be used for <em>so many</em> things - and we can&#39;t wait to learn what you will build.</p>
<h2 id="dependencies.swift" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies.swift<a href="#dependencies.swift" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies.swift"></a></h2>
<p>
We have all had our share of pain of using the SPM integration in Xcode. And more importantly, you can only integrate the SPM targets as sources - so when you inevitably clean your project, you need to <em>rebuild</em> all of the dependencies again. That&#39;s why a lot of users stick to using Carthage. You always integrate the targets as frameworks, never having to worry about building that code multiple times. Additionally, your Xcode projects is snappier because it only links binaries. The drawback of Carthage has always been that you as a developer have to do a lot of manual setup. And when the time comes and you have to debug your dependency, you need to go back to SPM or Cocoapods.</p>
<p>
With <a href="https://docs.old.tuist.io/manifests/dependencies/"><code class="inline">Dependencies.swift</code></a>, you declare your dependencies easily inside a dedicated Swift file instead of relying on Xcode UI. Your dependencies are resolved via a simple command <code class="inline">tuist fetch</code>. And then when you generate your project, tuist prebuilds all the dependencies, so you get a lean Xcode project which you can clean without worrying about ever having to rebuild your dependencies. And if you still want to debug a dependency, simply specify it in your <code class="inline">tuist generate</code> call.</p>
<p>
Now, <code class="inline">Dependencies.swift</code> has been around for a while but we <strong>declare it now as production-ready</strong>. That does not mean the work stops. We will continue working on bug fixes and improving this feature but we are quite confident that we cover most of the use-cases out there.</p>
<h2 id="cloud" tabindex="-1" class="marketing__blog_post__body__content__heading">
Cloud<a href="#cloud" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Cloud"></a></h2>
<p>
Users love caching - for both their own targets and maybe even more so for external ones from <code class="inline">Dependencies.swift</code>. As projects scale, compiling projects takes noticeably more time than when you started. But when you modularise your projects and integrate most of the targets as binaries, the project will be as joyful to work with as when you started. But wouldn&#39;t it be great if you could share what you have built across your team? Or even better, if the CI could build all the targets on each PR? Then you would always have to <strong>build just the part of the codebase you are working on</strong>. This is exactly what remote caching and tuist cloud aims to do - and we believe this will unlock such productivity that you can never achieve with using only what Apple provides (and you might never will).</p>
<p>
<strong>Tuist Cloud is now in an alpha version and ready to be used by first testers</strong>. You can follow the steps <a href="https://docs.old.tuist.io/cloud/get-started">here</a> to get yourself started. We appreciate any feedback - but also keep in mind the feature is still early in development. The feature is currently for free but consider donating <a href="https://opencollective.com/tuistapp">here</a> to support the development and help us pay the bills for keeping Tuist Cloud up and running.</p>
<p>
We have also recently started using Tuist Cloud for tuist itself - which was unlocked by our earlier work of defining tuist with tuist. This will enable us to catch any issues early in the process.</p>
<h2 id="looking-ahead" tabindex="-1" class="marketing__blog_post__body__content__heading">
Looking ahead<a href="#looking-ahead" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Looking ahead"></a></h2>
<p>
With tuist plugins being well-positioned now to cover lots of features that previously would have had to be built in tuist directly (such as the aforementioned <code class="inline">lint</code> command), we will focus on what makes tuist <em>special</em> - that is generating a project and caching. If a feature can be built without being directly involved in the generation or caching process, it should probably be a plugin.</p>
<p>
I expect we might see a lot of opportunities for improvement with Tuist Cloud - some features will be on the website only, some might need additional cooperation with tuist CLI. For example, I think we could provide statistics about build times and how they evolve over time. Since we already have <code class="inline">tuist build</code> command, it&#39;s only a matter of sending the right data to the server. But since Tuist Cloud is still nascent, new features will be decided based on the feedback we receive.</p>
<p>
Tuist is in a better position than ever to provide the best developer experience for developing on Apple platforms - and so the future is bright. I can&#39;t wait to see what we can build together next.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Releasing Tuist 2.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this post, we share more details about this new major version of the project, 2.0, and present the direction we are taking as we move towards 3.0. ]]></summary>
      <link href="https://tuist.dev/blog/2021/09/21/tuist-20"/>
      <id>https://tuist.dev/blog/2021/09/21/tuist-20</id>
      <updated>Tue, 21 Sep 2021 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
After over <a href="https://github.com/tuist/tuist/commits">5 thousand commits</a> from <a href="https://github.com/tuist/tuist/graphs/contributors">120 contributors</a> and over three years after we landed the first commit on the project,
I&#39;m thrilled to share with all of you that we released the second major version of the project, <a href="https://github.com/tuist/tuist/releases/tag/2.0.0">Tuist 2.0</a>.</p>
<p>
As you might know,
projects that follow <a href="https://semver.org/">semantic versioning</a> use major versions to flag breaking changes in the release.
From the user standpoint, that can be seen as unfavorable because the migration is usually manual.
However,
breaking changes are often necessary to continue to improve the developer experience (DX).
In this new major iteration of Tuist,
we&#39;re  <strong>moving away from poor API designs</strong>,
replacing some of them with <strong>more straightforward and convenient APIs</strong>,
and <strong>pruning features</strong> that were distant from the project&#39;s direction.</p>
<p>
Because the release already provides <a href="https://github.com/tuist/tuist/releases/tag/2.0.0">release notes and migration guidelines</a>,
I won&#39;t repeat myself,
and I&#39;ll get a bit philosophical in the paragraphs that follow to tell you more about what&#39;s coming in our path to Tuist 3.0.
Let&#39;s dive right in.</p>
<h2 id="evolving-our-plugins-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Evolving our plugins architecture<a href="#evolving-our-plugins-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Evolving our plugins architecture"></a></h2>
<p>
<a href="https://docs.old.tuist.io/plugins/using-plugins">Plugins</a> were born to allow developers to share primitives of Tuist projects.
In particular, they can share <a href="https://docs.old.tuist.io/guides/helpers">project description helpers</a> and <a href="https://docs.old.tuist.io/commands/task">tasks</a>.
Turning Tuist into an extensible <strong>platform</strong> was,
in hindsight,
a great idea.
Still, the approach we took failed to acknowledge that developers would want to depend on Swift packages from their plugins.
Extending our solution to support that would lead us to build a dependency manager.
As you can imagine,
that&#39;s not a good idea considering there are other package managers we can build upon.
Therefore we&#39;ll overhaul our plugins architecture to piggyback on the Swift Package Manager&#39;s work.
We are still fleshing out the details,
but without spoiling you too much,
plugins would be represented by Swift Packages that follow a convention defined by Tuist.
For example,
a task would become an executable in a Swift Package that follows the naming convention <code class="inline">tuist-{name}</code>.
Thanks to that,
developers can add transitive dependencies to their plugins,
and we can leverage the Swift Package Manager CLI to export the plugins in a distributable format.</p>
<p>
Checkout a more in depth RFC: <a href="https://github.com/tuist/tuist/discussions/3491">here</a></p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist plugin init # Creates a Swift Packagefollowing the plugin convetions
tuist plugin build # Builds the lugin using the &quot;swift&quot; CLI
tuist plugin test # Tests the plugin using the &quot;swift&quot; CLI
tuist plugin archive # Creates an pre-compiled archive to install the plugin    </shiki-highlight>
  </div>
</div>
<p>
Not only will third-party developers build for the platform,
but we&#39;ll also use it to extract some of the current commands that are more suitable to be opted into.
We can&#39;t wait to see what developers will build upon this new plugins architecture.</p>
<h2 id="caching-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Caching improvements<a href="#caching-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Caching improvements"></a></h2>
<p>
Improving build times remains one of the most concerning areas when scaling up Xcode projects.
Luckily,
our internal graph representation of projects positioned us to provide a solution without the complexity and maintenance of introducing a new build system like <a href="https://bazel.build/">Bazel</a> entails.
The idea is simple,
the project is represented by a graph with targets as nodes,
some of which can be replaced with their binary counterpart at generation time.
The binaries are identified with a fingerprint that changes if the target or any of its dependencies changes.
Sounds trivial, but it has a set of challenges.</p>
<p>
One of the challenges we are going through is getting a <strong>deterministic and accurate fingerprint</strong>.
It&#39;s challenging because Xcode projects support bringing implicitness to the build process.
For instance,
a script build phase could affect the built artifact of the target without the Tuist&#39;s fingerprinting logic being aware of it.
We can&#39;t detect implicitness,
but we can provide APIs to make it explicit.
Detecting sources of implicitness will require close collaboration with developers.</p>
<p>
Another challenge is <strong>generating a valid graph with binaries after the mutation.</strong>
The scenarios that we used as a reference are very ideal and,
in most cases, distant from reality.
There are many different flavors of Xcode projects out there that the mutation logic needs to handle gracefully.
If our mutation logic doesn&#39;t support them,
developers might end up getting a project that doesn&#39;t compile,
or even worse,
they won&#39;t get a project at all.</p>
<p>
When we adventured ourselves into the caching land,
we knew it was not going to be easy.
Our goal towards 3.0 is to continue to work with developers to make caching <strong>accessible and bulletproof</strong>.</p>
<h2 id="third-party-dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Third-party dependencies<a href="#third-party-dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Third-party dependencies"></a></h2>
<p>
Before we introduced <a href="https://docs.old.tuist.io/guides/third-party-dependencies"><code class="inline">Dependencies.swift</code></a>,
adding third-party dependency dependencies to a Tuist project was non-standard,
and in some scenarios,
led to integration issues that surfaced at compilation time.
Moreover,
the integration of Swift Packages proposed by Apple proved to offer a poor developer experience.
For example,
the resolution of dependencies sometimes fails at launch time,
and it gets invalidated after deleting the derivd data directory.</p>
<p>
<code class="inline">Dependencies.swift</code> offered a standard solution across Carthage and Package dependencies
and integrated dependencies into the projects&#39; graphs to allow users to leverage Tuist features.
One of those features is <code class="inline">tuist cache</code>,
which allows developers to cache their Swift Packages as binaries.
In the current state,
users can declare and integrate Carthage and Package dependencies,
but there seem to be some package scenarios that are not well merged into the graphs.
The consequence is that users get a project that doesn&#39;t compile.</p>
<p>
Because we believe in an integrated experience adding third-party dependencies,
we&#39;ll continue iterating through this functionality and make sure all the scenarios reported by users are handled gracefully.
If you are encountering issues,
please don&#39;t hesitate to <a href="https://github.com/tuist/tuist/issues/new?assignees=&labels=&template=Bug_report.md">file an issue</a> with a reproducible example.</p>
<h2 id="cloud" tabindex="-1" class="marketing__blog_post__body__content__heading">
Cloud<a href="#cloud" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Cloud"></a></h2>
<p>
For months,
we&#39;ve been pondering the idea of providing some workflows that require a server-side component:</p>
<ul>
  <li>
Remote binary caching.  </li>
  <li>
Share the local app running in your simulator with someone else.  </li>
  <li>
Get a dashboard with a project and build insights.  </li>
  <li>
Compare insights against a baseline (e.g., <code class="inline">main</code> branch) and post a report on a GitHub PR.  </li>
  <li>
Coordinate the process of releasing apps to the App Store.  </li>
</ul>
<p>
Moreover, the idea of providing an open-source web app paired nicely with finding a model to financially sustain the project to avoid falling into the same trap as projects like <a href="https://babeljs.io/">Babel</a>. Many companies depend on it, and they struggle to financially support people to work on it full-time.</p>
<p>
Therefore, towards Tuist 3.0, we&#39;ll build an open-source MIT-licensed web app, <strong>Tuist Cloud</strong>,
and provide hosting as a service.
Since it&#39;ll be open-source and the contract between the client and the server will be documented,
users will have the flexibility to bring their own implementation.
We won&#39;t fight against that,
but we are hopeful developers will acknowledge the importance of keeping the project alive and would opt for the path of paying for the service.</p>
<p>
The organization will remain a non-profit organization on <a href="https://opencollective.com/tuistapp">Open Collective</a>.
The revenue will be oriented towards having people working on Tuist and Tuist Cloud part or full-time..</p>
<p>
If you wanted to learn web development, Ruby, and Rails,
let us know,
and we&#39;ll be happy to pair with you on building new features for the project.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
Tuist 2.0 wouldn&#39;t have been possible without the continuous dedication of the project&#39;s core maintainers, contributors, and users.
They are the ones pushing the project beyond their limits and bringing new ideas to the table.
When I started the project back in 2018, I wouldn&#39;t have imagined there&#39;d be many of us on this boat solving such exciting challenges on top of a format like Xcode projects&#39; that is closed to extensibility.</p>
<p>
<strong>Tuist is here to stay</strong> because you&#39;ve proven to us there&#39;s a need for this tool in the industry.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Introducing plugins ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Plugins is a new feature that allows reusing Tuist building blocks across repositories. In this blog post we present the feature and how teams can leverage it to share project description helpers. ]]></summary>
      <link href="https://tuist.dev/blog/2021/02/12/introducing-plugins"/>
      <id>https://tuist.dev/blog/2021/02/12/introducing-plugins</id>
      <updated>Fri, 12 Feb 2021 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Building Tuist has taught us that there&#39;s <strong>an opportunity to share elements of your projects across repositories</strong>.
Let&#39;s say you work in an agency with projects scattered across several repositories.
In that scenario,
you might want your projects to be consistently structured to remove the cognitive load when jumping between projects.
That was not possible in Tuist.
The manifest files were tied to a repository.
Some projects tried to solve it by resorting to git submodules and cloning other repositories in specific directories to be seen by Tuist as local directories.
However, that was a workaround and not a proper solution.</p>
<p>
As a tool that helps teams with their challenges, it was a natural next step to allow teams to extract some Tuist elements into a separate repository and reuse them easily. The idea of building plugins was born.</p>
<h2 id="plugin.swift" tabindex="-1" class="marketing__blog_post__body__content__heading">
Plugin.swift<a href="#plugin.swift" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Plugin.swift"></a></h2>
<p>
A plugin is represented by a repository containing a <code class="inline">Plugin.swift</code> file and all the files that are part of the plugin. The current format of the manifest is simple, but we’ll continue to extend it as we add support for sharing more pieces:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let plugin = Plugin(name: &quot;MyPlugin&quot;)    </shiki-highlight>
  </div>
</div>
<p>
This first implementation of plugins only supports reusing helpers.
Those are defined under <code class="inline">ProjectDescriptionHelpers</code> like in the example below:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
.
├── ...
├── Plugin.swift
├── ProjectDescriptionHelpers
└── ...    </shiki-highlight>
  </div>
</div>
<h2 id="using-a-plugin" tabindex="-1" class="marketing__blog_post__body__content__heading">
Using a plugin<a href="#using-a-plugin" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Using a plugin"></a></h2>
<p>
Then users can declare the plugins in their projects&#39; <code class="inline">Config.swift</code> file. They can indicate if they&#39;d like the plugin to be read from a local directory or a remote repository <em>(commit or tag)</em>.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription
let config = Config(
    plugins: [
        .local(path: &quot;/Plugins/MyPlugin&quot;),
        .git(url: &quot;https://url/to/plugin.git&quot;, tag: &quot;1.0.0&quot;),
        .git(url: &quot;https://url/to/plugin.git&quot;, sha: &quot;e34c5ba&quot;)
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
As easy as that. Then you should be able to use the helpers from the plugin in your project by simply importing the plugin:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

import MyTuistPlugin
let project = Project.app(name: &quot;MyCoolApp&quot;, platform: .iOS)    </shiki-highlight>
  </div>
</div>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
Plugins are a powerful feature that opens the door to sharing content from your project with your organization&#39;s projects and the industry. Imagine coming up with a project architecture that you think is neat, and you&#39;d like to share it publicly. Companies used to do that through blog posts, but now, you can codify it into project description helpers and share them in a plugin 🤯.</p>
<p>
Moreover, we are planning to open a new interface for users to provide <strong>project transformations</strong> (mappers) that are applied at generation time. Once we have them available, we&#39;ll extend the plugins to support reusing them too.</p>
<p>
<a href="https://ppinera.es/2021/02/05/tuist-and-spm/">Unlike the Swift Package Manager</a>, we can be there right where our users need us. Listening to them and providing the features that they need to scale up their projects. If you are using Tuist, we encourage you to give plugins a shot and share thoughts and ideas in our <a href="https://github.com/tuist/tuist/discussions">community forum</a>. Thanks for reading.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Next for Tuist ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ It's a wrap for 2020. In this blog post we share the vision of Tuist for 2021. We'll bring support for plugins, improve and standardize the integration of third party dependencies, add support for selective building and testing, and much more. ]]></summary>
      <link href="https://tuist.dev/blog/2020/12/24/next-for-tuist"/>
      <id>https://tuist.dev/blog/2020/12/24/next-for-tuist</id>
      <updated>Thu, 24 Dec 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
It’s almost a wrap for 2020. It’s been a year to explore new possibilities that Xcode project generation enables and provide teams with streamlined workflows to build great apps for Apple platforms.</p>
<p>
In this blog post, I&#39;ll unfold the areas we’ll focus on in 2021.</p>
<h2 id="plugins" tabindex="-1" class="marketing__blog_post__body__content__heading">
Plugins<a href="#plugins" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Plugins"></a></h2>
<p>
With project generation, we gave teams a simple interface to describe their modular projects.
By design, we chose <a href="https://developer.apple.com/swift/">Swift</a> as the language for describing them.
It was a great idea because it allowed us to provide a great developer experience and features like <a href="https://docs.old.tuist.io/guides/helpers/">project description helpers</a>.</p>
<p>
As more projects adopted Tuist,
we realized it’d also be useful for teams to extract Tuist-related files into a different repository to make them organization-wide resources.
For example,
a company with templates defined in project description helpers could pull them into a separate repository,
and have access to them from multiple repositories.
This gave us the idea of introducing a new concept into Tuist, <strong>Plugins</strong>.</p>
<p>
A plugin is a new form of encapsulation to reuse user-defined Tuist primitives across projects.
Plugins will have a companion manifest file, <code class="inline">Plugin.swift</code>, which defines the plugin configuration:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let plugin = Plugin(
  projectDescriptionHelpers: true,
  templates: true
)    </shiki-highlight>
  </div>
</div>
<h2 id="standard-management-of-third-party-dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Standard management of third-party dependencies<a href="#standard-management-of-third-party-dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Standard management of third-party dependencies"></a></h2>
<p>
The integration between Tuist projects and the dependency managers is not ideal.
<a href="https://github.com/carthage">Carthage</a> frameworks can be declared as framework dependencies.
Still, the project generation might fail if developers forget to run the right Carthage command to fetch them.
When projects depend on <a href="https://cocoapods.org">CocoaPods</a>,
Tuist runs <code class="inline">pod install</code> after generating the project but can’t validate that the integration described in the <code class="inline">Podfile</code> is right.
That might result in projects that are seemingly right but that don’t compile.</p>
<p>
Finally,
Swift Package Manager is integrated at build time by leveraging Xcode’s integration with the Swift Package Manager.
That leads to a terrible developer experience because Xcode tries to resolve them at launch time.
If it fails,
the project is left in an unusable state.
Moreover,
packages that declare their products are static might lead to upstream duplicated symbol issues.</p>
<p>
We are very well-aware of this problem and therefore would like to do something from our side to provide a better developer experience integrating their third-party dependencies.
We believe a great developer experience revolves around a <strong>standard interface</strong> across dependency managers.
We&#39;ll achieve that by extracting the <strong>dependency graph resolution</strong> from the generation and launching of the project,
and <strong>integrating</strong> the third-party dependencies graph with the local graph.</p>
<h2 id="selective-building-and-testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Selective building and testing<a href="#selective-building-and-testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Selective building and testing"></a></h2>
<p>
In large projects,
building and testing all the project targets in <a href="https://en.wikipedia.org/wiki/Continuous_integration">continous integration (CI)</a> is inefficient;
only the targets that are impacted by the changes should be tested and built.
The common scenario that we find in large projects is a developer opening a tiny pull request, and having to wait half an hour to get all the green checks before merging.</p>
<p>
Since Tuist knows about the project dependency graph, and the changed files by using the underlying a version control tool (e.g. git),
it can combine that information with some other heuristics to provide selective building and testing and speed up developers&#39; workflows.</p>
<p>
By letting Tuist optimize the workflows, teams will automatically get optimizations introduced in future releases. Furthermore, they can focus their efforts on building the apps and not defining an efficient CI workflow.</p>
<h2 id="caching-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Caching improvements<a href="#caching-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Caching improvements"></a></h2>
<p>
In 2020 we introduced the concept of generating <strong>focused projects</strong>. Focused projects are projects optimized to work on a given target. For example, if I plan to work on app <code class="inline">MyApp</code> and the framework <code class="inline">MyAppSupport</code>, I can run <code class="inline">tuist focus MyApp MyAppSupport</code>, and Tuist will remove the targets that are not necessary to work on those targets, and replace direct and transitive dependencies with a precompiled versions of them. The latter is something that we refer to as <strong>caching</strong>.</p>
<p>
Unlike modern build systems like <a href="https://buck.build">Buck</a> and <a href="https://bazel.build">Bazel</a> that cache at the file level at the cost of taking developers away from Xcode&#39;s build system and having to keep up with Xcode updates, Tuist&#39;s caching works at the module level and using Xcode&#39;s build system. It provides a command, <code class="inline">tuist cache warm</code>, to precompile and cache every project&#39;s cacheable target.</p>
<p>
Caching works great with some ideal project scenarios. However, there are many complex project scenarios that we don&#39;t handle gracefully. For example, the caching of projects with transitive Swift Packages as dependencies doesn&#39;t work. It&#39;s not impossible, but it&#39;ll certainly require a fair amount of work. We are aligning our work on better management of third-party dependencies to allow their caching. By the end of 2021, we hope to cache most of the target types: <em>frameworks, libraries, bundles, and third-party dependencies.</em></p>
<h2 id="app-releasing" tabindex="-1" class="marketing__blog_post__body__content__heading">
App releasing<a href="#app-releasing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to App releasing"></a></h2>
<p>
Releasing an app involves many steps: bumping the app version, archiving the app, exporting it with the right signing profiles, and uploading it to Testflight. Tuist could streamline all of them into a single workflow that gets triggered by running:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
tuist release    </shiki-highlight>
  </div>
</div>
<p>
The command would work both locally and on CI, signing the app with the right provisioning profile and certificate, and authenticating and uploading the app through the <a href="https://developer.apple.com/app-store-connect/api/">App Store Connect API</a>.</p>
<h2 id="tuist-2.0" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist 2.0<a href="#tuist-2.0" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist 2.0"></a></h2>
<p>
Tuist&#39;s API has been very stable for the last few years, and we have a good amount of features to justify the release of a new major version. Therefore, 2021 will be the year when we&#39;ll release a new major version of Tuist, 2.0. To make this new release special, we are working on a <strong>redesign of our brand and website</strong>. We are taking the opportunity to revisit the website&#39;s content to ensure the ideas are clearly conveyed and that users can find what they are looking for easily.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
Tuist was born in 2016 out of the necessity for a tool to describe Xcode projects of any size using plain language. We built it upon a <strong>dependency graph</strong> representation, which enabled useful features such as project linting, workspaces, and the generation of focused projects. We chose Swift as a language because it felt natural to developers and allowed us to provide a great developer experience; developers could edit their projects using the editor and the programming language they were most familiar with. Moreover, they&#39;d get documentation, validation, auto-completion, and syntax-highlighting without having to leave Xcode.</p>
<p>
The natural next step to project generation was <strong>automation</strong>. For years the industry had settled on the idea of programming workflows using a programmable DSL like <a href="https://github.com/fastlane">Fastlane</a>, which acted like a glue between the terminal and the Xcode projects. However, with Tuist understanding your projects, Fastlane seemed an unnecessary layer of indirection. We could provide a streamlined experience through a standard set of commands that developers could familiarize themselves with. Like it happens with the Swift Package Manager, developers could use the same commands in any directory that contained a <code class="inline">Project.swift</code> or a <code class="inline">Workspace.swift</code>. <strong>Build and test</strong> were born.</p>
<p>
Fast forward to today, we are focusing our efforts around <strong>caching</strong> because we know it&#39;s the challenge many projects struggle a lot with. Neither replacing their build system nor spinning an infrastructure team is an option for most of them. We want to be there with those users and support them to scale up their projects.</p>
<p>
<strong>What comes after 2021?</strong> It&#39;s hard to say, but I can assure you that we&#39;ll work hard to make developer experience and productivity independent from the projects&#39; size.</p>
<p>
Happy end of 2020 🤗</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with Angry Nerds - Project description helpers are a game changer for modular apps ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we interview Marcel from Angry Nerds, a custom software development company based in Wrocław, Poland. Marcel talks about a wide range of topics which includes their workflows, preferred code patterns and architecture, and their testing strategy. ]]></summary>
      <link href="https://tuist.dev/blog/2020/11/27/angry-nerds"/>
      <id>https://tuist.dev/blog/2020/11/27/angry-nerds</id>
      <updated>Fri, 27 Nov 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In this post of our Apps at Scale series where we interview teams building apps at a large scale, we interview <a href="https://twitter.com/marcelstarczyk">Marcel</a>, iOS developer at <a href="https://twitter.com/angrynerds_soft">Angry Nerds</a>, a custom software development company based in Wrocław, Poland. Angry Nerds builds mobile apps for all kinds of industries, including education, entertainment, healthcare, transportation and more.</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="do-you-organize-yourselves-differently-depending-on-the-project?-if-so,-what-does-it-depend-on?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you organize yourselves differently depending on the project? If so, what does it depend on?<a href="#do-you-organize-yourselves-differently-depending-on-the-project?-if-so,-what-does-it-depend-on?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you organize yourselves differently depending on the project? If so, what does it depend on?"></a></h3>
<p>
Currently, the Angry Nerds iOS team consists of 7 developers, mostly mid- and senior-level. The number of team members engaged in a particular project usually depends on the client&#39;s requirements and the project&#39;s scope. Commonly, there&#39;s at least one iOS developer working in every mobile project. As for organizing the work, we run projects according to agile principles and best practices. We usually work in <strong>1- or 2-week sprints</strong> that allow us to be flexible towards changing requirements. <a href="https://en.wikipedia.org/wiki/CI/CD">CI/CD</a>, <a href="https://datasift.github.io/gitflow/IntroducingGitFlow.html">GitFlow</a> and regular code reviews are fundamental processes we apply to every project.</p>
<h3 id="how-do-developers-collaborate-with-designers-and-product-stakeholders?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do developers collaborate with designers and product stakeholders?<a href="#how-do-developers-collaborate-with-designers-and-product-stakeholders?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do developers collaborate with designers and product stakeholders?"></a></h3>
<p>
The collaboration with designers is practically seamless, as we have an in-house design team. We’re in constant communication and solve any issues almost instantly. Designers often consult their work with us, and the other way round, to assure consistency and make the teamwork more efficient. We also build close relationships with other stakeholders, including the clients. With daily communication and regular demos, we want to make the workflow and knowledge transfer as smooth as possible.</p>
<h2 id="project-and-code-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project and code architecture<a href="#project-and-code-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project and code architecture"></a></h2>
<h3 id="could-you-name-some-traits-that-are-common-to-every-project-and-therefore-you-need-them-to-be-consistent?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you name some traits that are common to every project and therefore you need them to be consistent?<a href="#could-you-name-some-traits-that-are-common-to-every-project-and-therefore-you-need-them-to-be-consistent?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you name some traits that are common to every project and therefore you need them to be consistent?"></a></h3>
<p>
First of all, our projects are open for the whole iOS team and code reviews across the projects are highly encouraged. The <code class="inline">yml</code> template definitions of our CI system pipelines are shared across projects. We have also CD definitions to reflect all changes made on the development branch that need to be tested by our QA team. As for pull requests, the template requirements are filled out by the developer who creates the particular PR. And of course, in all our projects we follow Xcode’s Clean Swift templates.</p>
<h3 id="how’s-the-process-of-creating-new-projects-and-ensuring-consistency?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How’s the process of creating new projects and ensuring consistency?<a href="#how’s-the-process-of-creating-new-projects-and-ensuring-consistency?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How’s the process of creating new projects and ensuring consistency?"></a></h3>
<p>
We are still in the process of finding the most effective way to create and manage our projects with consistency. We’ve tried using XcodeGen which has its definitions written in <code class="inline">yml</code>. It worked quite well but it didn’t feel native enough for us. After discovering Tuist and trying it on a sample project, we really appreciate the fact that the project definitions are written in an already known language, used by most iOS developers – Swift. We haven’t finished working on the process yet, but we are definitely getting closer to it everyday.</p>
<h3 id="what-strategy-do-you-follow-to-not-duplicate-efforts-across-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What strategy do you follow to not duplicate efforts across projects?<a href="#what-strategy-do-you-follow-to-not-duplicate-efforts-across-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What strategy do you follow to not duplicate efforts across projects?"></a></h3>
<p>
We try to discover and extract common APIs / code parts into one accessible place for our iOS team to reuse (and possibly improve in time). For example, we did it with Networking Layer code or most common Foundation extensions.</p>
<h3 id="do-you-have-a-fixed-way-to-organise-your-project-modules?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you have a fixed way to organise your project modules?<a href="#do-you-have-a-fixed-way-to-organise-your-project-modules?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you have a fixed way to organise your project modules?"></a></h3>
<p>
We do have modules that you could call our &quot;core&quot; modules, for example: the Design System module which encompases the app’s fonts, font styles and colors, the <code class="inline">CommonUI</code> module which contains all common views, assets etc. that other “feature” modules use, and the <code class="inline">Networking</code> module which includes the core of networking layer that other modules use. Other modules are created organically and based on particular features/requirements.</p>
<h3 id="what-code-architecture-do-you-usually-use-in-your-apps?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What code architecture do you usually use in your apps?<a href="#what-code-architecture-do-you-usually-use-in-your-apps?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What code architecture do you usually use in your apps?"></a></h3>
<p>
Most of our projects are now written using Clean Swift architecture which is based on Uncle Bob’s <a href="http://cleancoder.com/">Clean Code paradigm</a> of code separation. We also have some projects written using <a href="https://github.com/ReactiveX/RxSwift">RxSwift</a> + <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel">MVVM</a>.</p>
<h3 id="why-do-you-prefer-reactive-programming-over-other-paradigms?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Why do you prefer reactive programming over other paradigms?<a href="#why-do-you-prefer-reactive-programming-over-other-paradigms?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Why do you prefer reactive programming over other paradigms?"></a></h3>
<p>
We did some projects using reactive programming in the past, however right now, as our recent projects are utilizing the Clean Swift architecture, we tend not to use reactive paradigms in those. Code separation and unidirectional communication between the entities in Clean Swift’s modules are sufficient and the usage of reactive paradigms would not be as beneficial. Still, we are not against those paradigms. Lately, we&#39;ve been looking into <a href="https://github.com/pointfreeco/swift-composable-architecture">Swift Composable architecture</a> - its usage of reactive paradigms is actually very promising. We would like to try it out in some of our future projects.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<h3 id="how-do-you-manage-your-third-party-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you manage your third-party dependencies?<a href="#how-do-you-manage-your-third-party-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you manage your third-party dependencies?"></a></h3>
<p>
In most cases, we use <a href="https://swift.org/package-manager/">Swift Package Manager</a>. As a fallback, we practice manual addition to a project, if a particular dependency does not support SPM.</p>
<h3 id="what’s-a-third-party-dependency-your-project-heavily-depends-on?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s a third-party dependency your project heavily depends on?<a href="#what’s-a-third-party-dependency-your-project-heavily-depends-on?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s a third-party dependency your project heavily depends on?"></a></h3>
<p>
The key ones are: <a href="https://github.com/mac-cain13/R.swift">RSwift</a> for resources management, <a href="https://github.com/uber/needle">Needle</a> for Dependency Injection and <a href="https://github.com/Alamofire/Alamofire">Alamofire</a> for Networking purposes.</p>
<h3 id="what’s-your-take-on-external-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your take on external dependencies?<a href="#what’s-your-take-on-external-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your take on external dependencies?"></a></h3>
<p>
We think that dependencies that solve the core problems of the app (like Networking layer, AutoLayout definitions, Resource management or Dependency Injection) are fine to incorporate into a project as they are mostly well written, tested and maintained. We tend not to add external dependencies that solve app-specific problems, are not up-to-date or are no longer maintained by their creators (or the open source community).</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
In most projects, we try to cover core business logic with unit tests. We also add some <a href="https://softwaretestingfundamentals.com/smoke-testing">UI smoke tests</a>. Our goal is to cover as much as possible in Interactor and Presenter layers with unit tests. In some current projects we also use <a href="https://vapor.codes/">Swift Vapor</a> server to mock network traffic.</p>
<h3 id="how-do-you-balance-between-unit/integration/ui-tests?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you balance between unit/integration/ui tests?<a href="#how-do-you-balance-between-unit/integration/ui-tests?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you balance between unit/integration/ui tests?"></a></h3>
<p>
We follow a general principle that the number of unit tests should outweigh the number of integration tests.</p>
<h3 id="which-ones-give-you-more-confidence?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Which ones give you more confidence?<a href="#which-ones-give-you-more-confidence?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Which ones give you more confidence?"></a></h3>
<p>
We think that confidence comes from somewhere in-between unit and integration tests, as integration tests depend on unit tests, but they are worthless without quality unit tests.</p>
<h2 id="tooling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tooling<a href="#tooling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tooling"></a></h2>
<h3 id="what-are-the-tools-that-you-usually-set-up-in-your-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are the tools that you usually set up in your projects?<a href="#what-are-the-tools-that-you-usually-set-up-in-your-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are the tools that you usually set up in your projects?"></a></h3>
<p>
The essential ones are:</p>
<ul>
  <li>
<a href="https://github.com/mac-cain13/R.swift">Rswift</a>  </li>
  <li>
<a href="https://github.com/realm/SwiftLint">SwiftLint</a>  </li>
  <li>
<a href="https://github.com/nicklockwood/SwiftFormat">SwiftFormat</a>  </li>
  <li>
<a href="https://github.com/uber/needle">Needle</a> for DI  </li>
  <li>
<a href="https://github.com/SwiftyBeaver/SwiftyBeaver">Swiftybeaver</a> for logging  </li>
  <li>
<a href="https://github.com/airbnb/lottie-ios">Lottie</a>  </li>
  <li>
<a href="https://github.com/onevcat/Kingfisher">Kingfisher</a>  </li>
</ul>
<h2 id="tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist<a href="#tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist"></a></h2>
<h3 id="what-led-you-to-adopt-tuist?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What led you to adopt Tuist?<a href="#what-led-you-to-adopt-tuist?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What led you to adopt Tuist?"></a></h3>
<p>
As we’re constantly working on improving the way we build and manage our projects, we see Tuist as a great tool to support our efforts. To be more precise, we appreciate these particular things about Tuist and they were direct reasons why we decided to adopt the tool to our workflow:</p>
<ul>
  <li>
Project generation definitions written in Swift  </li>
  <li>
Less git conflicts when working on a single code base, thanks to pbxproj files non existent in the repository  </li>
  <li>
Clear and predictable CI pipelines based on Tuist API  </li>
  <li>
Less problems with bootstrapping projects (thanks to <code class="inline">Setup.swift</code> definitions and <code class="inline">tuist up</code> command)  </li>
  <li>
Explicit and clean project settings definitions which help us to clearly see new project’s modifications  </li>
  <li>
Easy dependency management of third party libraries, be it <a href="https://cocoapods.org">Cocoapods</a>, <a href="https://github.com/carthage">Carthage</a>, SPM or manual addition to project definition under one common API  </li>
  <li>
We were looking for a way to generate a new project (and its potential subprojects) quickly and effortlessly with one command and Tuist did just that for us.  </li>
</ul>
<h3 id="what-is-the-tuist-feature-that-you-like-the-most?-why?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is the Tuist feature that you like the most? Why?<a href="#what-is-the-tuist-feature-that-you-like-the-most?-why?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is the Tuist feature that you like the most? Why?"></a></h3>
<p>
<a href="https://docs.old.tuist.io/commands/up/">Tuist up</a> command - we really like the fact that we can provide the project’s dependencies to other developers beforehand, so they don&#39;t need to waste time on the tools setup and just do it all by executing one command. We also appreciate <a href="https://docs.old.tuist.io/commands/graph/">Tuist graph</a> command - because we can quickly show other developers the high level view of communication between all app’s modules.</p>
<h3 id="do-you-use-project-description-helpers?-if-so,-for-what?-would-you-mind-sharing-a-code-snippet?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use project description helpers? If so, for what? Would you mind sharing a code snippet?<a href="#do-you-use-project-description-helpers?-if-so,-for-what?-would-you-mind-sharing-a-code-snippet?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use project description helpers? If so, for what? Would you mind sharing a code snippet?"></a></h3>
<p>
Yes, we do! It’s a game changer for us while developing a project with separate modules. We have one common project definition with base settings and schemes which we use in a new module creation. It all comes down to new <code class="inline">Project.swift</code> file, e.g:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let project = Project.framework(name: &quot;NewModule&quot;,
                                targets: [.framework],
                                packages: [
                                  .package(url: &quot;https://github.com/airbnb/lottie-ios.git&quot;, from: &quot;3.1.6&quot;)
                                ],
                                externalDependencies: [.package(product: &quot;Lottie&quot;)],
                                internalDependencies: [
                                  &quot;Core&quot;,
                                  &quot;CommonUI&quot;,
                                  &quot;DesignSystem&quot;,
                                  &quot;Networking&quot;,
                                  &quot;Map&quot;,
                                  &quot;Rating&quot;,
                                  &quot;Settings&quot;
                                ],
                                resources: [
                                  .glob(pattern: &quot;**/*.swift&quot;),
                                  .glob(pattern: &quot;Resources/**&quot;)
                                ])    </shiki-highlight>
  </div>
</div>
<p>
And we have a new module ready for implementation!</p>
<h3 id="what’s-something-you-would-like-tuist-to-help-you-with?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s something you would like Tuist to help you with?<a href="#what’s-something-you-would-like-tuist-to-help-you-with?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s something you would like Tuist to help you with?"></a></h3>
<p>
To be honest, Tuist adds new features much faster than we are able to adopt them, so anytime we come up with an idea – it&#39;s there 😅 Still waiting for that run command though 🤞</p>
<h2 id="other" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other<a href="#other" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other"></a></h2>
<h3 id="what-were-you-most-excited-about-this-year’s-wwdc?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What were you most excited about this year’s WWDC?<a href="#what-were-you-most-excited-about-this-year’s-wwdc?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What were you most excited about this year’s WWDC?"></a></h3>
<p>
<a href="https://developer.apple.com/app-clips/">AppClips</a> look very promising. Also ARKit advancements are something we are looking forward to, as we have a project coming up in the pipeline, which will make extensive use of it.</p>
<h3 id="what-is-the-project-you-are-most-proud-of-in-terms-of-technical-challenge?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What is the project you are most proud of in terms of technical challenge?<a href="#what-is-the-project-you-are-most-proud-of-in-terms-of-technical-challenge?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What is the project you are most proud of in terms of technical challenge?"></a></h3>
<p>
Our recent favorite is <a href="https://angrynerds.co/projects/cats-and-dogs-the-weather-app/">Cats and Dogs: The Weather App</a>, a gamified weather app we created with a UK-based creative agency. The key purpose of the app is that apart from receiving a reliable weather forecast, you get to take care of a virtual pet and earn bonuses for dressing it according to the weather. The client provided all the designs, including over 10K (!) animations which are the very heart of the project. They were also one of the biggest challenges in development, as it required weeks of detailed work to integrate the animations and sounds with the app’s features. We’re really proud of how it turned out! The app has been created with MVVM + Coordinators architecture and RxSwift library, and for the animations we used Lottie.
We’ve also been a long-term partner to an international optoelectronics company, working with them on a complex mobile app for hunters, with such features as ballistics calculator, GPS assistance and more. There are also many exciting projects we worked on that we can’t mention because of the NDA agreements with our clients.</p>
<h3 id="have-you-accommodated-your-work-style-to-these-unprecedented-times?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Have you accommodated your work style to these unprecedented times?<a href="#have-you-accommodated-your-work-style-to-these-unprecedented-times?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Have you accommodated your work style to these unprecedented times?"></a></h3>
<p>
It was quite impressive that a team of over 70 people switched to remote work basically overnight – and it went so smoothly. We are seriously blessed that our work can be done virtually from any place in the world with good internet connection. I think we should acknowledge it a little more. As much as we’re used to remote work right now, we look forward to meeting once again in the office with the rest of the Angry Nerds team!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with George Tsifrikas - What led us to modularize Workable's project was high build times ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this interview of apps at scale we interview George Tsifrikas, iOS team lead at Workable. He shares his experience growing their Xcode project into a modular app, how they use reactive programming extensively throughout the app, and the testing strategies that they follow to ship new features with confidence. ]]></summary>
      <link href="https://tuist.dev/blog/2020/10/08/george"/>
      <id>https://tuist.dev/blog/2020/10/08/george</id>
      <updated>Thu, 08 Oct 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In this new post of our &quot;Apps at scale&quot; series, we interview <a href="https://twitter.com/gtsifrikas">George Tsifrikas</a>, iOS team lead at Workable. George talks about their experience modularizing the Xcode project with CocoaPods to improve build-times and how that led them to build their own dependency injection framework, Inject. Moreover, he dives into their testing strategy and feature flags solution to allow teams to confidently deliver features. Without further ado, let&#39;s dive right into the interview.</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="how-are-the-teams-structured?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How are the teams structured?<a href="#how-are-the-teams-structured?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How are the teams structured?"></a></h3>
<p>
The engineering teams at Workable are formed per a specific area in our product (video interviews, referrals, core.) except the mobile team. The mobile team is responsible for iOS and Android apps. It develops all the features that make sense to be on the mobile app and is not separated into feature squads.</p>
<h3 id="how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many engineers work on features and how many take care of the infrastructure of your projects?<a href="#how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many engineers work on features and how many take care of the infrastructure of your projects?"></a></h3>
<p>
I hope to have a dedicated mobile infrastructure team sometime in the future, but we are not there yet. We are a small iOS team to get to do features and infrastructure for our app.</p>
<h3 id="how-do-designers-and-developers-collaborate?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do designers and developers collaborate?<a href="#how-do-designers-and-developers-collaborate?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do designers and developers collaborate?"></a></h3>
<p>
When we plan a new feature, our designer has a leeway of two weeks before implementing a feature. During that time, the mobile platform leads, and designers discuss how it could be implemented and any potential constraints. During the two weeks before the implementation, there is a lot of back and forth, mainly in the form of comments in <a href="https://figma.com">Figma</a>.</p>
<p>
Upon starting the implementation of a feature, we may change a few things here and there. Maybe we couldn’t predict a use case but almost always stick to the design we started with. In the middle of the sprint, we do some catch-up between Android, iOS, and our designer to showcase our progress and align platform designs. Also, at that time, we correct some UI/UX issues that may come up. Generally, throughout the sprint, our designer receives staging builds, and she gives us feedback if we have missed something.</p>
<h2 id="project" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project<a href="#project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project"></a></h2>
<h3 id="what-led-you-to-modularize-your-app?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What led you to modularize your app?<a href="#what-led-you-to-modularize-your-app?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What led you to modularize your app?"></a></h3>
<p>
The one major thing was and mainly still is, compile times. As our project grew, so the compile times. Waiting 2 minutes for an incremental build and 8 minutes for a clean build was just painful, killing productivity.</p>
<h3 id="what-did-you-learn-during-the-process-of-modularizing-the-app?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What did you learn during the process of modularizing the app?<a href="#what-did-you-learn-during-the-process-of-modularizing-the-app?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What did you learn during the process of modularizing the app?"></a></h3>
<p>
It was a way more significant undertaking of an effort that we had in our minds when designing the modularisation. First, we did a lot of research on how the code should be separated. Not properly separating the code it may even increase the compile times of clean builds. Then, we tried to determine how we will support the modularisation effort in terms of the project&#39;s organization. We didn&#39;t want to create each module by hand each in a separate Xcode project because, for each module, we would have to pass all the build settings and how these are connected between them by hand, which would make the whole configuration tiresome and prone to errors.</p>
<p>
We used <a href="https://cocoapods.org">CocoaPods</a> with custom templates that we had declared our module once, and everything worked (almost). We had to change many build settings in the Podfile and do some other hacks to have <a href="https://nshipster.com/ibinspectable-ibdesignable/">IBDesignable</a> to render in the storyboards. Right now, we are in the process of evaluating Tuist. When you start splitting your code, you want to do it incrementally, especially if it is a large codebase. So, we started from the Core module with swift extensions, networking, and almost everything shared between every feature. We tried to keep Core-like modules in small numbers, so right now, we have, <code class="inline">WorkableUIKit</code>, <code class="inline">UIComponents</code>, <code class="inline">Models</code>, <code class="inline">ModelsDecoding</code>, <code class="inline">Interfaces</code>, <code class="inline">Event</code> (our first feature module), and <code class="inline">Inject</code>.</p>
<h3 id="have-you-developed-any-core-module-that-you-would-like-to-share-with-the-industry?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Have you developed any core module that you would like to share with the industry?<a href="#have-you-developed-any-core-module-that-you-would-like-to-share-with-the-industry?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Have you developed any core module that you would like to share with the industry?"></a></h3>
<p>
When you try to split code between modules to achieve fast build times, you need to reduce the interdependencies in code-level and module-level. For example, you have a shop app that shows a product listing, and you add the product to the cart and start the checkout process. Let&#39;s assume that the product listing functionality is implemented in the <code class="inline">Product</code> module and the checkout in the <code class="inline">Checkout</code> module. Ideally, you don&#39;t want the <code class="inline">Product</code> module to know anything about the <code class="inline">Checkout</code> module, not even its existence, except how to call it.</p>
<p>
In our case, we have a dependency inversion layer that we have all the public protocols we want to share between our modules. In the previous example, the <code class="inline">Product</code> module can import <code class="inline">Interfaces</code> and use the <code class="inline">Checkout</code> module functionality, right? Almost, we need an instance for the concrete class inside the <code class="inline">Checkout</code> module that implements the protocol from Interfaces.</p>
<p>
In our Workable app until then, we were doing dependency injection using constructors. Sometimes we weren&#39;t diligent or didn&#39;t pass the dependencies from the root <em>(AppDelegate)</em>. So, we needed a solution that is easy to use, and it didn&#39;t feel like a chore. So, we <strong>created our own dependency injection library <code class="inline">Inject</code></strong>. <code class="inline">Inject</code> uses property wrappers to <em>&quot;inject&quot;</em> properties anywhere you want by merely writing @Injected in front of the property.</p>
<h3 id="can-you-tell-us-more-about-how-you-use-property-wrappers-to-do-dependency-injection?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Can you tell us more about how you use property wrappers to do dependency injection?<a href="#can-you-tell-us-more-about-how-you-use-property-wrappers-to-do-dependency-injection?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Can you tell us more about how you use property wrappers to do dependency injection?"></a></h3>
<p>
Let&#39;s assume you have the following property in your code:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
@Injected var fooInstance: Foo    </shiki-highlight>
  </div>
</div>
<p>
Firstly, <code class="inline">Foo</code> must be a protocol. How Inject in our app finds the implementation of <code class="inline">Foo</code>? In our <code class="inline">AppDelegate</code> when the app starts we register to <code class="inline">Inject</code> all dependencies. But we found out that you will encounter two major issues when you do runtime registering and dependency resolving. The first one is that you may have dependency cycles without realizing it. Let&#39;s say we have <code class="inline">Foo</code> and <code class="inline">Bar</code> protocols with <code class="inline">FooImpl</code> and <code class="inline">BarImpl</code>. If you use in <code class="inline">FooImpl</code> an injected property of <code class="inline">Bar</code> and in <code class="inline">BarImpl</code> and injected property of <code class="inline">Foo</code> you will have a dependency cycle and while your app compiles, it will crash from stack overflow when it tries to use one of either of these classes. The solution for this was to create a little analyzer that uses <code class="inline">Swift</code>&#39;s mirroring and does <code class="inline">DFS</code> throughout the dependency graph looking for cycles. If it finds one, it shows you the cycle to break it.</p>
<p>
The second one was that you may again use the:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
@Injected var fooInstance: Foo    </shiki-highlight>
  </div>
</div>
<p>
and never registered how the <code class="inline">Foo</code> is initialized. Again the app will compile, but it will crash from <code class="inline">Inject</code>, saying that it didn&#39;t find a way to instantiate the <code class="inline">Foo</code> property. The solution for that is a little linter that runs from Xcode, like <a href="https://github.com/realm/SwiftLint">SwiftLint</a>. For example, it parses your codebase and finds out for each Injected property if it is registered. Suppose it finds out that one is not. In that case, it shows an Xcode error directly on the line for the unregistered dependency prompting you to register it. It really made it very enjoyable to use dependencies correctly and everywhere.</p>
<p>
We hope to make it open source very, very soon!</p>
<h2 id="code" tabindex="-1" class="marketing__blog_post__body__content__heading">
Code<a href="#code" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Code"></a></h2>
<h3 id="could-you-briefly-describe-the-architecture-of-your-app-and-the-paradigms-that-you-follow?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you briefly describe the architecture of your app and the paradigms that you follow?<a href="#could-you-briefly-describe-the-architecture-of-your-app-and-the-paradigms-that-you-follow?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you briefly describe the architecture of your app and the paradigms that you follow?"></a></h3>
<p>
We&#39;re big fans of reactive programming, and we&#39;re using <a href="https://github.com/ReactiveX/RxSwift">RxSwift</a> from the start of the app. So all the data flows are done by observables. Each feature we write uses <a href="https://github.com/RossSong/RxMVVM">RxMVVM</a>, which enables us to write very comprehensive tests, especially for each screen&#39;s logic. For each feature, we have an entry point. For example, to compose a new email from the candidate screen all we have to do is, <code class="inline">emailComposer.new(forCandidate:) -&gt; Observable&lt;Void&gt;</code> , note email composer is injected to the candidate screen. Also, we are using our own Swift Error handler to have uniform error handling across the app.</p>
<h3 id="how-do-you-ensure-consistency-across-the-codebase-(style,-architecture)?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you ensure consistency across the codebase (style, architecture)?<a href="#how-do-you-ensure-consistency-across-the-codebase-(style,-architecture)?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you ensure consistency across the codebase (style, architecture)?"></a></h3>
<p>
Nothing fancy here; we try to document everything we can, Swift style guide, Code architecture, How we test, and everything we can think of. Right now that we&#39;re hiring, it will prove very useful for our team&#39;s new members. We enforce the styling of the code with SwiftLint.</p>
<h2 id="processes/workflows" tabindex="-1" class="marketing__blog_post__body__content__heading">
Processes/Workflows<a href="#processes/workflows" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Processes/Workflows"></a></h2>
<h3 id="how-is-the-process-since-there’s-an-idea-for-a-feature-until-it-lands-on-the-main-branch-(e.g.-master)?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How is the process since there’s an idea for a feature until it lands on the main branch (e.g. master)?<a href="#how-is-the-process-since-there’s-an-idea-for-a-feature-until-it-lands-on-the-main-branch-(e.g.-master)?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How is the process since there’s an idea for a feature until it lands on the main branch (e.g. master)?"></a></h3>
<p>
You can think of our apps as an extension of the Workable desktop app. When we decide to do a new feature, we decide which aspects make sense to be on mobile apps. Our mobile team leads and designer start working on the feature at least two weeks before its planned start date. After that, we start to do design meetings, and we start implementing the feature. Each work is closed to our main branch through a PR. It doesn&#39;t have to be complete, just not to break existing functionality. We try to keep small PRs so as not to spend much time reviewing significant changes. We can close PRs frequently because we use local feature flags. That means we can start a new feature behind a flag, and we ship unfinished work, but the end-user never gets to see that work. We use TestFlight to distribute staging builds to the designers and Product Managers through a custom pipeline created in Jenkins. As developers, we get frequent feedback, which lets us quickly fix things and iterate repeatedly. After we finish a feature, the PM responsible for this feature green-light it, and we ship it to the next release.</p>
<h3 id="how-do-you-define-feature-flags?-do-you-use-a-service-for-that-or-is-there-an-in-house-solution?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you define feature flags? Do you use a service for that or is there an in-house solution?<a href="#how-do-you-define-feature-flags?-do-you-use-a-service-for-that-or-is-there-an-in-house-solution?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you define feature flags? Do you use a service for that or is there an in-house solution?"></a></h3>
<p>
The feature flags are just boolean values inside a plist file. We do not use them for A/B testing or remote launch of a feature. These are only for our convenience. It helps us avoid merging huge branches with many conflicts between each other, and each developer gets to work with the more &quot;real&quot; version of the code.</p>
<h3 id="when-do-you-consider-a-feature-“shippable”?" tabindex="-1" class="marketing__blog_post__body__content__heading">
When do you consider a feature “shippable”?<a href="#when-do-you-consider-a-feature-“shippable”?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to When do you consider a feature “shippable”?"></a></h3>
<p>
A feature is shippable when our designer has approved it and our PM. We have agreed on a timeline with other teams if there is an inter-dependency. Also, for essential features, a feature is shippable when we have fully end-to-end automated tests.</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
We try to adhere to Martin Fowler&#39;s &quot;the practical testing pyramid&quot; as much as we can. For us, that means that we do a small number of end-to-end tests using Appium, which for our work and as integration tests. We try to have 80% coverage or more with unit tests and snapshot tests in each feature enforced by our CI pipelines on our PRs. Because our ETE tests are flaky sometimes and we need a lot of time to write them, we checked with our QA team and found out that almost all of our regressions are API related. That means that a response from the backend changed in a not agreed-upon way. So, we try to introduce another way of testing, which is called contract-testing using PACT. Our client and the backend have a contract that is validated in the unit tests of each platform. This type of testing is way quicker than running ETE tests, which take 3-4 hours. Our plan is to migrate less used features from the ETE suite to the contract suite to gain time and stability.</p>
<h3 id="do-you-rely-on-third-party-libraries-for-writing-your-tests?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you rely on third-party libraries for writing your tests?<a href="#do-you-rely-on-third-party-libraries-for-writing-your-tests?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you rely on third-party libraries for writing your tests?"></a></h3>
<ul>
  <li>
<strong>ETE:</strong> appium  </li>
  <li>
<strong>Unit tests:</strong> Quick  </li>
  <li>
<strong>Snapshots:</strong> nimble snapshot (works in cohort with Quick)  </li>
  <li>
<strong>Contract tests:</strong> PACT  </li>
</ul>
<h3 id="do-you-have-a-qa-team?-if-so,-what’s-their-role?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you have a QA team? If so, what’s their role?<a href="#do-you-have-a-qa-team?-if-so,-what’s-their-role?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you have a QA team? If so, what’s their role?"></a></h3>
<p>
We have a QA engineer who is responsible for both iOS &amp; Android. The responsibilities are maintaining the test suite, CI/CD pipeline, and coordinating the release with other teams. The actual ETE tests are written by mobile engineers.</p>
<h3 id="what-led-you-to-write-more-snapshot-and-pact-tests?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What led you to write more snapshot and PACT tests?<a href="#what-led-you-to-write-more-snapshot-and-pact-tests?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What led you to write more snapshot and PACT tests?"></a></h3>
<p>
For years we relied heavily on end-to-end tests. All this time, the app grew, and along with it, the ETE suite. This brought some problems with it. The suite now takes several hours to run. When you have multiple teams inside Workable who want to make their own releases, each team must wait for the ETE suite to pass to check that there are no regressions. As I mentioned above, we checked with our QA engineer and found out that many of the regressions that the ETE suite found were breaking API changes. We can use contract testing to cover this aspect of testing fast and stable as unit tests. Now, the suite caught some UI regressions, and we introduced snapshot testing in our feature development. This lets us check for any UI regression, and also it generates a visual diff if something breaks!</p>
<h3 id="how-do-you-describe-your-pact-tests-and-when-do-you-run-them?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you describe your PACT tests and when do you run them?<a href="#how-do-you-describe-your-pact-tests-and-when-do-you-run-them?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you describe your PACT tests and when do you run them?"></a></h3>
<p>
PACT tests are written in Swift. Essentially you describe the request to the backend and the expected result format. Then you verify in your test that you can parse that expected response. The contract is driven by the client. The backend is the consumer of that contract that must comply with. If any team wants to change an API that affects us, they have to contact the mobile team to schedule any necessary changes. Now the test runs in each commit in an open PR. We have a status page that shows the branch of the backend repo with the branch of iOS or Android and if the contact is verified in that configuration.</p>
<h2 id="tooling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tooling<a href="#tooling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tooling"></a></h2>
<h3 id="what-internal-tools-did-you-build-that-you-are-proud-of?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What internal tools did you build that you are proud of?<a href="#what-internal-tools-did-you-build-that-you-are-proud-of?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What internal tools did you build that you are proud of?"></a></h3>
<p>
The only internal tooling we have done so far for iOS was making CocoaPods the declaring modules mechanism. Making this work involved a lot of time learning about libraries, frameworks, dylib, etc. Not the best solution overall, but we may not have moved on with the modules without this.</p>
<h3 id="what-are-your-main-challenges-on-tooling-when-scaling?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are your main challenges on tooling when scaling?<a href="#what-are-your-main-challenges-on-tooling-when-scaling?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are your main challenges on tooling when scaling?"></a></h3>
<p>
The lack of proper tooling from Apple. We should have a more versatile solution for building and organizing our code. SPM is a step in the right direction, but it&#39;s still early.</p>
<h3 id="what-are-some-challenges-you-are-facing-scaling-up-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are some challenges you are facing scaling up your project?<a href="#what-are-some-challenges-you-are-facing-scaling-up-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are some challenges you are facing scaling up your project?"></a></h3>
<p>
The biggest one I would say is consistency in the code. When the project gets quite big, people come and go it&#39;s difficult to communicate what has been implemented and where. For example, we may find the same Swift extension implemented multiple times with slightly different names. Documentation and anticipation of where to find something is essential.</p>
<h2 id="last-but-not-least" tabindex="-1" class="marketing__blog_post__body__content__heading">
Last but not least<a href="#last-but-not-least" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Last but not least"></a></h2>
<h3 id="if-you-started-the-project-again,-what-would-you-do-differently?" tabindex="-1" class="marketing__blog_post__body__content__heading">
If you started the project again, what would you do differently?<a href="#if-you-started-the-project-again,-what-would-you-do-differently?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to If you started the project again, what would you do differently?"></a></h3>
<p>
Focus more on code readability and organization. It is essential to have a certain way to do things initially but willing to change it if it doesn&#39;t fit requirements anymore.</p>
<h3 id="what-are-you-the-most-excited-about-for-wwdc?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are you the most excited about for WWDC?<a href="#what-are-you-the-most-excited-about-for-wwdc?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are you the most excited about for WWDC?"></a></h3>
<p>
From the software side, I really liked widgets and how they were implemented using SwiftUI to achieve such an excellent performance (serializing the SwiftUI on disk). From the hardware side, of course, Apple Silicon. I&#39;m really excited about the future form factors and performance of hardware with Apple&#39;s own chip.</p>
<h3 id="how-did-covid-19-impact-your-work-style-and-processes?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How did COVID-19 impact your work style and processes?<a href="#how-did-covid-19-impact-your-work-style-and-processes?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How did COVID-19 impact your work style and processes?"></a></h3>
<p>
Before COVID-19, almost all of our engineering was done on premises in our beautiful Athens offices. When the Greek government announced the lock-down, we were promptly forced to start working from home. We had one day per week that we could work from home until then, but this is totally different from remote working. We had to change the way we communicate, which translated to more documentation. Everything must have a place so anyone can find it easily, fewer meetings, and trying to have a more async way of communication.</p>
<h3 id="how-do-you-favour-asynchronous-communication-over-synchronous-one?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you favour asynchronous communication over synchronous one?<a href="#how-do-you-favour-asynchronous-communication-over-synchronous-one?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you favour asynchronous communication over synchronous one?"></a></h3>
<p>
At first, anyone working from the office had the expectation of getting an answer to a question relatively quickly. When you migrate to the async way of communication, it is a little bit difficult because you have to wait or do something else if you are blocked by someone. Still, I believe this a small price to pay because you have the flexibility when to respond to someone, which is less distracting from the work you focused on right now. If someone answers you in Slack, you can go back later and see the answer again (but it probably should be documented somewhere).</p>
<h3 id="how-do-you-make-sure-everyone-is-on-the-same-page-with-a-distributed-team-setup?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you make sure everyone is on the same page with a distributed team setup?<a href="#how-do-you-make-sure-everyone-is-on-the-same-page-with-a-distributed-team-setup?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you make sure everyone is on the same page with a distributed team setup?"></a></h3>
<p>
We use a knowledge base (<a href="https://www.atlassian.com/software/confluence">Confluence</a>) for features or any research that we do in various ways. For technical stuff, we use markdown on GitHub. We&#39;re lucky our team is in the same timezone, and we have many overlapping hours between us, so later in the day, we do a catch-up meeting to get on the same page. Our goal is to eliminate that and use Trello or something similar to sync upon how we&#39;re doing.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ 1.18.0 Himalaya - Documentation generation, Swift interface for accessing resources, and code linting ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist 1.18.0 is packed with interesting automatomation feature that will streamline developers' workflows further. This new version provides commands for auto-generating documentation and linting the Swift code, and integrates the generation of Swift interfaces for resources into the project generation. ]]></summary>
      <link href="https://tuist.dev/blog/2020/09/16/version-1180"/>
      <id>https://tuist.dev/blog/2020/09/16/version-1180</id>
      <updated>Wed, 16 Sep 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
One of the areas that Tuist started exploring further since we hit version 1.0 is automation. The primary motivation was providing a more standard and better-integrated experience to users by leveraging the knowledge Tuist has on users’ projects. Since then, we have seen great features like <code class="inline">tuist build</code> landing in the project.</p>
<p>
Unlike other automation tools like <a href="https://fastlane.tools">Fastlane</a>, Tuist doesn’t installing of third-party packages through tools like <a href="https://brew.sh">Homebrew</a>, or having a Ruby environment configured, leading to well-known reproducibility issues. Tuist’s automation puts <strong>developer’s experience over flexibility</strong>, even if that means going a bit off the industry standards.</p>
<p>
There’s a huge opportunity to build standard automation that is <strong>easy, deterministic, and works reliably</strong>. Today we are taking a step further and bringing <strong>three major features</strong> in our latest release 1.18.0. Let’s dive right into them.</p>
<h2 id="generate-documentation-for-your-targets" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generate documentation for your targets<a href="#generate-documentation-for-your-targets" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generate documentation for your targets"></a></h2>
<p>
When working in a modular code base, users might need to consume the public API implemented by another target (e.g., target). nless the user is already familiar with the API, it’s useful to have documentation that users can read through to understand better what’s available and how they can use it.
Other programming environments like Rust, provide a <code class="inline">doc</code> command through their package manager, <a href="https://doc.rust-lang.org/cargo/">Cargo</a>. However, that’s not a thing in Xcode nor the Swift Package Manager, and for that reason, we are taking inspiration from Cargo and bringing the functionality to Xcode’s land. Since Tuist 1.18.0, users can run the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist doc MyFramework    </shiki-highlight>
  </div>
</div>
<p>
The command generates documentation for the given target using <a href="https://github.com/SwiftDocOrg/swift-doc">swift-doc</a> by <a href="https://twitter.com/mattt">Mattt</a> and opens it on the browser for users to check it out. Once they are done checking out the documentation, Tuist deletes it automatically.</p>
<p>
The image below shows an example of auto-generated documentation:</p>
<p>
  <img src="/marketing/images/blog/2020/09/16/documentation.png" alt="An image that shows a browser with the auto-generated documentation">
</p>
<p>
You can read more about the feature <a href="https://docs.old.tuist.io/commands/documentation/">here</a>.</p>
<h2 id="auto-generate-swift-interfaces-for-type-safe-access-to-resources" tabindex="-1" class="marketing__blog_post__body__content__heading">
Auto-generate Swift interfaces for type-safe access to resources<a href="#auto-generate-swift-interfaces-for-type-safe-access-to-resources" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Auto-generate Swift interfaces for type-safe access to resources"></a></h2>
<p>
One of the downsides of accessing resources using strings is that nothing prevents developers from using an invalid string and releasing an app where some resources are missing in the UI. What&#39;s worse, the app crashes because the implementation expects a resource to be available. <a href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a> solved that problem by generating Swift interfaces to access the resources that belong to a target.</p>
<p>
We think it&#39;s a brilliant idea worth incorporating into Tuist, and that&#39;s what we did in this release. Tuist automatically generates a Swift interface for accessing the resources and adds it to the target automatically. Users don&#39;t have to install SwiftGen, ensure that their targets are well-configured, or add extra lanes into their <code class="inline">Fastfiles</code>. The generation of those interfaces happens seamlessly at project generation time.</p>
<p>
You can check out <a href="https://docs.old.tuist.io/guides/resources/">this documentation page</a> to learn more about the feature.</p>
<h2 id="lint-your-swift-code" tabindex="-1" class="marketing__blog_post__body__content__heading">
Lint your Swift code<a href="#lint-your-swift-code" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Lint your Swift code"></a></h2>
<p>
In large teams, it becomes essential to have a set of code style guidelines that ensures everyone uses the same style when writing Swift. Teams usually achieve that with widely-used tools like <a href="https://github.com/realm/SwiftLint">SwiftLint</a>.</p>
<p>
Tuist 1.18.0 integrates that functionality into a new command that takes care of calling SwiftLint with the right arguments depending on users&#39; intents:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
tuist lint code
tuist lint code MyTarget    </shiki-highlight>
  </div>
</div>
<p>
You can read more about the functionality and how to provide your SwiftLint configuration on <a href="https://docs.old.tuist.io/commands/linting/">this page</a>.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
We are continuing to invest in automation. We&#39;ll soon start working on <code class="inline">tuist test</code> to be able to run tests directly from the terminal. Moreover, we are planning the work on a standard interface for defining third-party dependencies. It has been in our backlog for a long time and that we finally set out to tackle.</p>
<p>
Besides that, we are also investing in caching and insights to help boost developers&#39; productivity and provide teams with insights about their projects that allow them to make informed decisions.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ 1.14.0 Spezi, a release packed with improvements ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we present the improvements and bug fixes that we included in the version of Tuist 1.14.0 ]]></summary>
      <link href="https://tuist.dev/blog/2020/07/24/version-1140"/>
      <id>https://tuist.dev/blog/2020/07/24/version-1140</id>
      <updated>Fri, 24 Jul 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hola 👋,</p>
<p>
It&#39;s Friday, and that means time for a new Tuist release. With the aim of releasing more often, we are pushing out a new release, 1.14.0, which we named after <a href="https://en.wikipedia.org/wiki/Spezi">Paulaner&#39;s Spezi</a>. We are not including major features in this release, but a lot of minor improvements and fixes that will make the experience of using Tuist better. In this also-short blog post, I&#39;ll go through those improvements and bug fixes that are part of the release:</p>
<h3 id="disable-swiftlint-in-the-generated-source-files" tabindex="-1" class="marketing__blog_post__body__content__heading">
Disable SwiftLint in the generated source files<a href="#disable-swiftlint-in-the-generated-source-files" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Disable SwiftLint in the generated source files"></a></h3>
<p>
With the introduction of <a href="https://docs.old.tuist.io/guides/resources/">synthesized accessors for resources</a> some users reported that SwiftLint failed because it linted the generated files. We <a href="https://github.com/tuist/tuist/pull/1574">fixed</a> it by adding annotations in the generated files to disable <a href="https://github.com/realm/SwiftLint">SwiftLint</a> in them.</p>
<h3 id="fix-the-path-resolution-for-synthesized-resource-accessors" tabindex="-1" class="marketing__blog_post__body__content__heading">
Fix the path resolution for synthesized resource accessors<a href="#fix-the-path-resolution-for-synthesized-resource-accessors" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Fix the path resolution for synthesized resource accessors"></a></h3>
<p>
Continuing with fixes in the synthesized resource accessors, some users reported that <code class="inline">Bundle.module</code> returns an invalid <code class="inline">Bundle</code> when the target is a framework or an app. That&#39;s already <a href="https://github.com/tuist/tuist/pull/1575">fixed</a> in Tuist 1.14.0</p>
<h3 id="read-core-data-version-from-.xcurrentversion" tabindex="-1" class="marketing__blog_post__body__content__heading">
Read Core Data version from .xcurrentversion<a href="#read-core-data-version-from-.xcurrentversion" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Read Core Data version from .xcurrentversion"></a></h3>
<p>
Before this version, developers had to specify the version of the current Core Data model in the project manifest. Since that&#39;s information that is already defined in the file <code class="inline">.xcurrentversion</code> file, users ended up with two sources of truth for the same attribute. From <a href="https://github.com/tuist/tuist/pull/1572">this version</a>, <code class="inline">.xcurrentversion</code> is used as the source of truth.</p>
<h3 id="support-generating-projects-with-targets-from-the-cache" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support generating projects with targets from the cache<a href="#support-generating-projects-with-targets-from-the-cache" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support generating projects with targets from the cache"></a></h3>
<p>
We added support for the <code class="inline">--cache</code> argument to the <code class="inline">generate</code> command. It used to be an argument only supported by the <code class="inline">focus</code> command, but now developers can also generate projects with targets from the cache.</p>
<h3 id="improve-error-when-a-target-has-the-same-dependency-defined-twice." tabindex="-1" class="marketing__blog_post__body__content__heading">
Improve error when a target has the same dependency defined twice.<a href="#improve-error-when-a-target-has-the-same-dependency-defined-twice." class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Improve error when a target has the same dependency defined twice."></a></h3>
<p>
We&#39;ve improved the error thrown when a target has the same dependency defined more than once. The error <a href="https://github.com/tuist/tuist/pull/1573">now includes</a> the name of the target.</p>
<p>
And that&#39;s it for this week. We wish you all a happy weekend, and we&#39;ll be back next Friday with a new release and more and better features to make the experience of working with Xcode great.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Local caching of frameworks with Tuist 1.13.0 Bella Vita ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we introduce Tuist 1.13.0 Bella Vita. It's is a huge leap forward for Tuist because it introduces a new feature, local cache, to help teams speed up their buidls. This version also ships with significant improvements and some bug fixes. ]]></summary>
      <link href="https://tuist.dev/blog/2020/07/20/version-1130"/>
      <id>https://tuist.dev/blog/2020/07/20/version-1130</id>
      <updated>Mon, 20 Jul 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
It&#39;s been quiet and productive weeks for Tuist.
We silently shipped a new version, Tuist 1.12.0,
and just yesterday,
we shipped the version 1.13.0,
which we called <strong>Bella Vita</strong>.</p>
<p>
In this blog post,
I&#39;ll tell you about major features that we shipped in these two releases,
as well as minor improvements and bug fixes that continue to improve the stability and the performance of the tool.
Let&#39;s dive right in.</p>
<h2 id="local-caching" tabindex="-1" class="marketing__blog_post__body__content__heading">
Local caching<a href="#local-caching" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Local caching"></a></h2>
<p>
As you might know,
as projects get larger, one of the challenges teams often face is slow builds.
Xcode has an incremental build system that tries to reuse results from past compilations to make builds faster.
The problem though is that developers are used to using <strong>CMD+K</strong> when the compilation on Xcode yields errors.
That invalidates Xcode&#39;s cache and results in a clean build.</p>
<p>
Some projects minimize the build time of clean builds by having a more horizontal project architecture <em>(e.g., <a href="https://docs.old.tuist.io/building-at-scale/microfeatures/">µFeatures architecture</a>)</em>. Large companies prefer to replace Xcode&#39;s build system with other build systems like <a href="https://bazel.build">Bazel</a> or <a href="https://buck.build/">Buck</a> that the output of individual build steps remotely. Unfortunately, the latter is a huge undertaking that is not feasible for small and medium companies.</p>
<p>
In Tuist, we aim to help teams with the challenges they face when scaling up projects, which was an obvious one to tackle.</p>
<p>
Tuist 1.13.0 ships with a new feature, <strong>cache</strong>, which allows generating projects replacing dependencies with their pre-compiled version. To use this feature, developers can use the following 2 commands.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
tuist cache warm
tuist focus --cache    </shiki-highlight>
  </div>
</div>
<p>
When we <strong>warm the cache</strong>, we build all frameworks as xcframeworks and store them in a local directory. They are uniquely identified by a hash that is calculated based on the target attributes, project, dependencies, and the environment (e.g. Tuist and Swift version). Developers can run <code class="inline">tuist cache warm</code> locally after cloning the project or changing between branches. In the future, projects will be able to run that from CI, and Tuist will be able to pull them from cloud storage (this is already being worked on).</p>
<p>
After warming the cache, developers can run <code class="inline">tuist focus --cache</code> which reads as: <em>I want to focus on the project in this directory, please, replace the dependencies (if possible) with their xcframework from the cache</em>. For instance, if you plan to work on <code class="inline">MyApp</code>, all the direct and transitive dependencies that <code class="inline">MyApp</code> depends on will be xcframeworks. That means even if you use CMD+K, you&#39;ll always be compiling just <code class="inline">MyApp</code>.</p>
<p>
<strong>If you want to know more about the feature</strong>, you can read our page <a href="https://docs.old.tuist.io/building-at-scale/caching/"><strong>Caching dependencies</strong></a> in the documentation.</p>
<h2 id="minor-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Minor improvements<a href="#minor-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Minor improvements"></a></h2>
<h4 id="clean" tabindex="-1" class="marketing__blog_post__body__content__heading">
Clean<a href="#clean" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Clean"></a></h4>
<p>
Some Tuist features use a local cache to have a better performance. Until this version, the only way to clean the cache was by deleting the <code class="inline">~/.tuist/Chache</code> manually. Fortunately, that&#39;s not necessary anymore because developers can now run <a href="https://github.com/tuist/tuist/pull/1516"><code class="inline">tuis clean</code></a>.</p>
<h4 id="secret" tabindex="-1" class="marketing__blog_post__body__content__heading">
Secret<a href="#secret" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Secret"></a></h4>
<p>
Tuist&#39;s signing management requires a secret key under the <code class="inline">Tuist</code> directory that is used for encrypting and decrypting the certificates. To generate cryptographically secured key, there&#39;s now a new command <a href="https://github.com/tuist/tuist/pull/1471"><code class="inline">tuist secret</code></a> that generates and outputs a random key.</p>
<h4 id="invalid-globs" tabindex="-1" class="marketing__blog_post__body__content__heading">
Invalid globs<a href="#invalid-globs" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Invalid globs"></a></h4>
<p>
Unlike Xcode projects, with Tuist developers can use glob patterns such as <code class="inline">Sources/**/*.swift</code> to specify a group of files.
When a glob pattern pointed to a non-existing directory, it resulted in an empty group of files, and developers wondering why files were missing.
We changed that by <a href="https://github.com/tuist/tuist/pull/1523">adding a check</a> that verifies if the pattern is valid. Now if developers use an invalid pattern, the generation of projects will fail and tell them why.</p>
<h4 id="upward-search-for-the-setup.swift-file" tabindex="-1" class="marketing__blog_post__body__content__heading">
Upward search for the Setup.swift file<a href="#upward-search-for-the-setup.swift-file" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Upward search for the Setup.swift file"></a></h4>
<p>
<code class="inline">tuist up</code> only worked when the directory where it was run from contained a <code class="inline">Setup.swift</code>.
From this version, we <a href="https://github.com/tuist/tuist/pull/1513">changed the behavior</a> to do an upwards lookup. For example, given the following scenario:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
/Setup.swift
/Projects
  /App
    Project.swift    </shiki-highlight>
  </div>
</div>
<p>
Running <code class="inline">tuist up</code> under <code class="inline">Projects/App</code> would use the root <code class="inline">Setup.swift</code>.</p>
<h4 id="edit-projects-with-the-select-xcode-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
Edit projects with the select Xcode project<a href="#edit-projects-with-the-select-xcode-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Edit projects with the select Xcode project"></a></h4>
<p>
<code class="inline">tuist edit</code> ignored the selected Xcode version when opening the project for editing the manifests. That&#39;s <a href="https://github.com/tuist/tuist/pull/1511">fixed now</a>. <code class="inline">tuist edit</code> will read the selected Xcode version and use that one instead.</p>
<h4 id="generate-a-graph-without-test-targets-and-external-dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generate a graph without test targets and external dependencies<a href="#generate-a-graph-without-test-targets-and-external-dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generate a graph without test targets and external dependencies"></a></h4>
<p>
<code class="inline">tuist graph</code> has now <a href="https://github.com/tuist/tuist/pull/1540">support</a> for not including test targets and external dependencies in the generated graph:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist graph --skip-test-targets --skip-external-dependencies    </shiki-highlight>
  </div>
</div>
<h2 id="bug-fixes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug fixes<a href="#bug-fixes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug fixes"></a></h2>
<h4 id="set-core-data-models-as-sources" tabindex="-1" class="marketing__blog_post__body__content__heading">
Set Core Data models as sources<a href="#set-core-data-models-as-sources" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Set Core Data models as sources"></a></h4>
<p>
There was a bug in the generation logic that added Core Data models as resources instead of sources. With <a href="https://github.com/tuist/tuist/pull/1542">this fix</a> they are now added as sources (as Xcode expects them).</p>
<h4 id="encoding-of-swift-packages" tabindex="-1" class="marketing__blog_post__body__content__heading">
Encoding of Swift packages<a href="#encoding-of-swift-packages" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Encoding of Swift packages"></a></h4>
<p>
<a href="https://github.com/tuist/tuist/pull/1558">There was a bug</a> in the logic that encodes/decodes the definition of a Package dependency that broke the generation of projects when the package requirement was a revision. That&#39;s fixed now.</p>
<h4 id="use-homebrew-which" tabindex="-1" class="marketing__blog_post__body__content__heading">
Use Homebrew which<a href="#use-homebrew-which" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Use Homebrew which"></a></h4>
<p>
<code class="inline">tuist up</code> failed to detect is a Homebrew formula was installed when the name of the formula didn&#39;t match the executable name. As <a href="https://github.com/tuist/tuist/pull/1544">described in this PR</a>, we are now using Homebrew&#39;s list command.</p>
<h4 id="auto-generated-schemes-for-extensions" tabindex="-1" class="marketing__blog_post__body__content__heading">
Auto-generated schemes for extensions<a href="#auto-generated-schemes-for-extensions" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Auto-generated schemes for extensions"></a></h4>
<p>
We have <a href="https://github.com/tuist/tuist/pull/1545">fixed</a> a bug that caused the auto-generated schemes for extensions to fail at launching them.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with Franz Busch - We are now using Combine as our Reactive framework and it makes development so much better ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this interview we talk with Franz Busch, iOS Developer at Sixt, a mobility provider. Franz shares how the adoption of the RIBs and Combine significantly improved the development experience and allowed them to have a very good test coverage. ]]></summary>
      <link href="https://tuist.dev/blog/2020/07/06/franz"/>
      <id>https://tuist.dev/blog/2020/07/06/franz</id>
      <updated>Mon, 06 Jul 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Continuing with our series of interviews about companies doing app development at scale, we are pleased to have <a href="https://twitter.com/FranzJBusch">Franz Busch</a>, iOS Developer at <a href="https://es.wikipedia.org/wiki/Sixt">Sixt</a>. As a mobility provider, Sixt has unique challenges, like integrating with car SDKs, that led the company to adopt a modular architecture using Uber&#39;s RIB approach and develop features following the reactive paradigm with Combine.</p>
<h2 id="tell-us-more-about-yourself-and-the-project-you-work-on" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tell us more about yourself and the project you work on<a href="#tell-us-more-about-yourself-and-the-project-you-work-on" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tell us more about yourself and the project you work on"></a></h2>
<p>
I have been developing iOS apps for the past 8 years and started at <a href="https://www.sixt.de/">Sixt</a> in 2016. Back then we were still developing our applications in Objective-C and only had a team of 3 people per platform. Since, then we grew tremendously both in team and app size which resulted in an increased complexity as well. Nowadays, we are not only a car rental company anymore but transformed into a true mobility provider. Our application has a broad range of products from the classic car rental to car sharing and scooters. Additionally, we launched last year the integration of our own ride hailing platform which is available world wide and just 2 weeks ago we launched our new car subscription product. About 2 years ago I created our internal <strong>platform team</strong> which is responsible for CI/CD, our build setup, internal libraries and a bunch of shared processes.</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="how-are-the-teams-structured?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How are the teams structured?<a href="#how-are-the-teams-structured?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How are the teams structured?"></a></h3>
<p>
We have <strong>5 teams</strong> working in our application at the moment. Each team is responsible for certain domains. For example one team is responsible for our car rental product and the other for the whole account section. The only team that has no direct domain is our platform team which takes care about a lot of shared libraries.</p>
<h3 id="how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many engineers work on features and how many take care of the infrastructure of your projects?<a href="#how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many engineers work on features and how many take care of the infrastructure of your projects?"></a></h3>
<p>
8-10 work on features and 2 on infra per platform.</p>
<h2 id="project-and-code-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project and code architecture<a href="#project-and-code-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project and code architecture"></a></h2>
<h3 id="could-you-describe-the-architecture-of-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you describe the architecture of your project?<a href="#could-you-describe-the-architecture-of-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you describe the architecture of your project?"></a></h3>
<p>
We started off with the classic <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a> architecture. After, 2 years of development we noticed that we are running into the same problems again and again and that collaboration between teams wasn’t the best since MVC can be interpreted quite broadly. Lastly, the testability &amp; reusability of our code wasn’t the best; therefore, we decided to move forward with a <a href="https://github.com/uber/RIBs">RIB architecture</a> and are currently undergoing a migration. We have finished a lot already. The best part about this is, that we are now using <a href="https://developer.apple.com/documentation/combine">Combine</a> as our Reactive framework and it makes development so much better!</p>
<h3 id="what-code-paradigms-and-architectures-do-you-follow?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What code paradigms and architectures do you follow?<a href="#what-code-paradigms-and-architectures-do-you-follow?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What code paradigms and architectures do you follow?"></a></h3>
<p>
As said before we use RIBs and FRP with Combine. Additionally, we are in the process of modularizing our applicaton heavily. Some other interesting things we are doing: Design System, UI in code, Single responsibility, generate code when possible.</p>
<h3 id="if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" tabindex="-1" class="marketing__blog_post__body__content__heading">
If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?<a href="#if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?"></a></h3>
<p>
We have a bunch of internal libraries that fulfill always only one purpose and be very good at that. For example, we have a library with all our UI components or one for formatting. We call these libraries <code class="inline">CoreModules</code> and they are shared among all our applicatons. On top of them, we build so-called <code class="inline">BusinessModules</code> that are then implementing specific flows. For example we have a <code class="inline">BusinessModule</code> that handles the <code class="inline">SixtLoginRegister</code> flow, which is specific to one application. Sometimes, these <code class="inline">BusinessModules</code> can be shared but most often they are specific to one app.</p>
<h3 id="what-are-the-main-challenges-on-your-architecture-when-scaling?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are the main challenges on your architecture when scaling?<a href="#what-are-the-main-challenges-on-your-architecture-when-scaling?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are the main challenges on your architecture when scaling?"></a></h3>
<p>
The architecture can scale quite heavily as shown by <a href="https://www.uber.com/de/en/">Uber</a>. The biggest challenges are probably to keep the dependency graph sane and the build times low.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<h3 id="how-do-you-manage-your-third-party-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you manage your third-party dependencies?<a href="#how-do-you-manage-your-third-party-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you manage your third-party dependencies?"></a></h3>
<p>
Right now we are still integrating them through <a href="https://github.com/carthage/carthage">Carthage</a> but plan to move over to SPM as soon as Xcode 12 hits GM. We have a bunch of binary dependencies which will be supported by Xcode 12 🥳.</p>
<h3 id="what’s-a-third-party-dependency-your-project-heavily-depends-on?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s a third-party dependency your project heavily depends on?<a href="#what’s-a-third-party-dependency-your-project-heavily-depends-on?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s a third-party dependency your project heavily depends on?"></a></h3>
<p>
We do not heavily rely on any third party dependency, since we are always trying to hide dependencies behind protocols. However, since we are a interacting with cars a lot we are quite relient on the car vendor SDKs to communicate with the cars.</p>
<h3 id="what’s-your-take-on-external-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your take on external dependencies?<a href="#what’s-your-take-on-external-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your take on external dependencies?"></a></h3>
<p>
Keep the number low and if possible build them internally. If that is not possible always hide them behind protocols, so that no logic is directly relying on them. This allowed us oftentimes to switch the underlying dependency without anybody noticing it.</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
Our focus is heavy on unit testing. In our old MVC architecture we had quite a bunch of problems with testability. Nowadays, with RIBs almost all of our business logic is testable and we are requiring tests for all new code. Additionally, our <code class="inline">CoreModules</code> need to be test covered quite extensively since we have to rely on them in the business logic layer. For our UI components and also screens we are using snapshot tests to make sure that the UI looks and behaves like we want it to. This allows us to move fast on the UI as well without breaking anything. We also have a whole testing team that takes care about manual and automated tests written in Appium. This allows us to release every 2 weeks with confidence.</p>
<h3 id="do-you-use-third-party-frameworks-for-testing?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use third-party frameworks for testing?<a href="#do-you-use-third-party-frameworks-for-testing?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use third-party frameworks for testing?"></a></h3>
<p>
In the beginning, we used <a href="https://github.com/Quick/Nimble">Nimble</a> but decided to migrate to <a href="https://developer.apple.com/documentation/xctest">XCTest</a> since it provides everything we need. For snapshot testing we use the <a href="https://github.com/pointfreeco/swift-snapshot-testing">library from Pointfree</a>. Lately, we have written our own <code class="inline">CombineTestHelpers</code> to make testing of Combine based code easier.</p>
<h3 id="how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?<a href="#how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?"></a></h3>
<p>
<strong>2,5k unit + snapshot tests</strong>. No integration or UI tests from our side. However, a lot of UI automation tests for all of our core flows from our test team. The unit tests give us the most confidence right now since the migration to RIBs we cover all of our business logic which is the most crucial to test.</p>
<h2 id="tooling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tooling<a href="#tooling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tooling"></a></h2>
<h3 id="what-internal-tools-did-you-build-that-you-are-proud-of?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What internal tools did you build that you are proud of?<a href="#what-internal-tools-did-you-build-that-you-are-proud-of?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What internal tools did you build that you are proud of?"></a></h3>
<p>
A tool to download &amp; organize all of our translations which is quite handy and fast!
A tool that lints XIB &amp; Storyboard files e.g. to disallow usage of images in them or check that nothing is ambiguous.
We have an internal debug screen which allows to hook new subscreens in dynamically. For example when transitioning to a certain screen it can register an associated debug screen which allows for better debugging.</p>
<h3 id="what-are-your-main-challenges-on-tooling-when-scaling?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are your main challenges on tooling when scaling?<a href="#what-are-your-main-challenges-on-tooling-when-scaling?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are your main challenges on tooling when scaling?"></a></h3>
<p>
When scaling, the performance of tools is very important. Especially, when these tools need to run during build time. Additionally, in larger projects you need to be careful when using code generation during build phases since it can hinder fast incremental builds quite drastically. Lastly, tools should be used when there is a big potential for critical bugs such as API contracts. API clients &amp; server stubs should be generated by tools to avoid any misinterpretations.</p>
<h3 id="what-are-some-challenges-you-are-facing-scaling-up-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are some challenges you are facing scaling up your project?<a href="#what-are-some-challenges-you-are-facing-scaling-up-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are some challenges you are facing scaling up your project?"></a></h3>
<p>
Definitely <strong>build time</strong>. The bigger the project gets the harder it becomes to track dependencies and also code that is slow to compile. Keeping on top of this is nearly a fulltime job. We were thinking about moving to <a href="https://bazel.build/">Bazel</a> for a long time now to make use of remote caching. Our ultimate goal is to provide developers fast iterative development.</p>
<h2 id="build-times" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build times<a href="#build-times" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build times"></a></h2>
<h3 id="what’s-your-cold-start-build-time,-and-what-are-your-plans-to-improve-it" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your cold start build time, and what are your plans to improve it<a href="#what’s-your-cold-start-build-time,-and-what-are-your-plans-to-improve-it" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your cold start build time, and what are your plans to improve it"></a></h3>
<p>
Our build time for clean builds is 300 seconds.</p>
<h2 id="tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist<a href="#tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist"></a></h2>
<h3 id="what-motivates-you-to-consider-the-adoption-of-tuist?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What motivates you to consider the adoption of Tuist?<a href="#what-motivates-you-to-consider-the-adoption-of-tuist?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What motivates you to consider the adoption of Tuist?"></a></h3>
<p>
Right now we are using <a href="https://github.com/yonaskolb/xcodegen">XcodeGen</a> for our project. While this made it already 100 times better than before it has certain limitations. First, it does not allow scripting. We have some build phases that need to get all the dependencies and pass it to a command. This is right now hard coded and required manual updating. Additionally, the YAML format is not the best to code-review and write. Lastly, it does not help us with improving build performance. With Tuist we hope to tackle of these. Especially the focus mode and pre-build dependencies would be great. A killer feature for Tuist would be integrating with Bazel. Right now this is rather cumbersome and has some very hard problems like debugging support. The people at <a href="https://lyft.com">Lyft</a> made tremendous improvements there and if there would be an easy to use solution would be awesome.</p>
<h2 id="other" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other<a href="#other" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other"></a></h2>
<h3 id="if-you-started-the-project-again,-what-would-you-do-differently?" tabindex="-1" class="marketing__blog_post__body__content__heading">
If you started the project again, what would you do differently?<a href="#if-you-started-the-project-again,-what-would-you-do-differently?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to If you started the project again, what would you do differently?"></a></h3>
<p>
Choose an architecture that covers these problems from the beginning: <em>high testability, common dependency injection strategy, modulare, single responsibility, supports asynchronous in app routing, uses FRP.</em>
From a build perspective: Start with modularisation right way and try to keep the main target as slim as possible. Additionally start with something like Tuist right away. If there is enough experience or capacity use Bazel.
On a side note, I think for any bigger app having a design system from the beginning makes creating new UIs way easier and the whole UX feels more coherent.</p>
<h3 id="what’s-the-announcement-that-excited-you-the-most-from-wwdc?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s the announcement that excited you the most from WWDC?<a href="#what’s-the-announcement-that-excited-you-the-most-from-wwdc?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s the announcement that excited you the most from WWDC?"></a></h3>
<p>
There is a lot in it for us. Apple Silicone means we need to look into our iOS app on Mac which is interesting. For our project probably the advancements in <a href="https://github.com/apple/swift-package-manager">SwiftPM</a>. <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a> seems to get better and better and we are really looking forward to use it at some point.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with Søren Gregersen - Anyone in the team can create and maintain Xcode projects easily ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this interview we talk with Søren Gregersen, co-founder of Emplate, a digital studio based in Denmark. Søren shared with us how they use Tuist and the project description helpers for one of their main projects, a white label app for shopping malls in Europe. ]]></summary>
      <link href="https://tuist.dev/blog/2020/06/28/soren"/>
      <id>https://tuist.dev/blog/2020/06/28/soren</id>
      <updated>Sun, 28 Jun 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In this interview, we talk with Søren Gregersen, co-founder of <a href="https://www.facebook.com/emplateaps/">Emplate</a>, a software studio based in Aarhus, Denmark. Emplate has been a heavy user of Tuist since they started using it in its early days. They&#39;ve provided a lot of valuable feedback to make Tuist better and help other projects that face challenges maintaining and scaling up Xcode projects.</p>
<p>
Without further delay, let&#39;s dive right into the interview:</p>
<h3 id="tell-us-more-about-yourself-and-the-project-you-work-on" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tell us more about yourself and the project you work on<a href="#tell-us-more-about-yourself-and-the-project-you-work-on" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tell us more about yourself and the project you work on"></a></h3>
<p>
I am <a href="https://twitter.com/SorenSHG">Søren</a> from Denmark. During university I co-founded a company called <a href="https://www.emplate.it/">Emplate</a> together with some good friends. I have been tinkering with computers and software for +15 years and I love building things and solving problems.</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="how-are-the-teams-structured?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How are the teams structured?<a href="#how-are-the-teams-structured?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How are the teams structured?"></a></h3>
<p>
Our company is still fairly small and we are 13 people in total. The product team consists of 7 people. We have two people working together on Android and two on iOS. My co-founder and I are also a part of the product team working on both our API, web-apps and also some Android/iOS. Apart from developers we also have a product designer working on everything from concept development to usability testing to marketing material.
The product team is a hybrid remote team spread across Europe which gives a lot of opportunities and challenges at the same time.</p>
<h3 id="how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many engineers work on features and how many take care of the infrastructure of your projects?<a href="#how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many engineers work on features and how many take care of the infrastructure of your projects?"></a></h3>
<p>
We try to leverage tools that can help us not spending too much time on infrastructure work. This is one of the things Tuist has helped us a lot with as we went from having one person knowing about how the Xcode projects were configured and meant to be used to having it documented in the manifest files. This also means we do not have any people dedicated to only working on infrastructure or features - we share the tasks and responsibilities between us.</p>
<h2 id="project-and-code-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project and code architecture<a href="#project-and-code-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project and code architecture"></a></h2>
<h3 id="could-you-describe-the-architecture-of-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you describe the architecture of your project?<a href="#could-you-describe-the-architecture-of-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you describe the architecture of your project?"></a></h3>
<p>
Our main project is a white label app for the guests in the shopping malls we work with. The app is currently available for +20 shopping malls across Europe in different variations. We use a strategy pattern to configure the app per shopping mall which allows us to customize them with different features, UI components etc. The Xcode structure is set up around multiple projects. One project with the app targets where the only source code is the AppDelegate + the configuration of each app. All app targets depend on a single framework in another Xcode project that contains the main part of the features. We do also have other separate frameworks containing network code, utility helpers, analytics code etc. Tuist has made this setup much more enjoyable and maintainable as we can set up a new framework project in a few minutes and make sure all frameworks are configured exactly the same.</p>
<h3 id="what-code-paradigms-and-architectures-do-you-follow?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What code paradigms and architectures do you follow?<a href="#what-code-paradigms-and-architectures-do-you-follow?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What code paradigms and architectures do you follow?"></a></h3>
<p>
We use a basic implementation of the <a href="https://www.objc.io/issues/13-architecture/viper/">VIPER</a> architecture. The benefit of using that architecture is that it provides a fairly clear definition of where to put certain kinds of code in a given module. This makes it easy for multiple developers to work together. Another benefit I like about VIPER is that it’s making testing our business logic very easy. The downside is that it might require a few more files and types than other architectures but using an Xcode template allows us to set up a new module in a few clicks.</p>
<h3 id="if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" tabindex="-1" class="marketing__blog_post__body__content__heading">
If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?<a href="#if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?"></a></h3>
<p>
We have two app projects in Emplate - a white label app for the guests in shopping malls and a managing app for the staff across the shopping malls. The way we share code between the two projects is unfortunately by duplicating the code between them. We are looking into using the Swift Package Manager to start building some internal frameworks to be able to share code more conveniently.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<h3 id="how-do-you-manage-your-third-party-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you manage your third-party dependencies?<a href="#how-do-you-manage-your-third-party-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you manage your third-party dependencies?"></a></h3>
<p>
We use <a href="https://github.com/carthage/carthage">Carthage</a> for managing third-party dependencies. To speed up build time on the CI and decrease the required project setup steps we track the built dependencies in a git submodule in the project.</p>
<h3 id="what’s-a-third-party-dependency-your-project-heavily-depends-on?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s a third-party dependency your project heavily depends on?<a href="#what’s-a-third-party-dependency-your-project-heavily-depends-on?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s a third-party dependency your project heavily depends on?"></a></h3>
<p>
Our projects depends heavily on <a href="https://github.com/ReactiveX/RxSwift">RxSwift</a> and <a href="https://texturegroup.org/">Texture</a> <em>(formerly known as AsyncDisplayKit)</em> for UI. We have been using these two dependencies for couple of years and they are in use in a large part of the projects at the moment.</p>
<h3 id="what’s-your-take-on-external-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your take on external dependencies?<a href="#what’s-your-take-on-external-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your take on external dependencies?"></a></h3>
<p>
I think external dependencies give a great way to leverage other people’s work and avoid having to reinvent the wheel over and over again. We try to limit the amount of dependencies we pull in and to not get locked in by them. We have experienced several issues with third party code when upgrading to new Xcode and iOS versions which is not fun to spend time on.</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
We try to cover all business logic with unit tests. This comes as a natural thing as we tend to practice <a href="https://en.wikipedia.org/wiki/Test-driven_development">TDD</a>. In the VIPER modules we always cover the presenter with unit tests <em>(as close to 100% coverage as possible)</em> with mocked view, router and interactor. In modules where the interactor has more complex responsibilities we also test those.
We also use the unit tests as a kind of documentation of the features in the apps and especially how edge cases are handled. It also gives the team members great confidence when touching other parts of the code base at a later point in time.</p>
<h3 id="do-you-use-third-party-frameworks-for-testing?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use third-party frameworks for testing?<a href="#do-you-use-third-party-frameworks-for-testing?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use third-party frameworks for testing?"></a></h3>
<p>
We use <a href="https://github.com/MakeAWishFoundation/SwiftyMocky">SwiftyMocky</a> to generate mock implementations of protocols which saves a lot of time writing boilerplate code when setting up a new test. I believe it has to be as simple as possible to get going with a new test case to keep the coverage high.</p>
<h3 id="how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?<a href="#how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?"></a></h3>
<p>
We mainly use unit tests and have +500 unit tests across our two projects. We have simple UI smoke tests that verifies the apps can launch and allows the user to click around the main features. This UI test is also used for generating screenshots for App Store using Fastlane.</p>
<h2 id="tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist<a href="#tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist"></a></h2>
<h3 id="what-led-you-to-adopt-tuist?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What led you to adopt Tuist?<a href="#what-led-you-to-adopt-tuist?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What led you to adopt Tuist?"></a></h3>
<p>
Adding a new app to the white-label project required too many manual clicks and drag/drop actions in Xcode that we had to keep a long list of steps to remember. Setting up a new app could take up to 45 minutes. After adopting Tuist the setup of a new app is down to a few easy steps using the scaffold command and is only taking around 15 minutes and can be done by the whole team. No more remembering and dragging and dropping inside Xcode 🎉</p>
<p>
Apart from the setup of new apps it also turned out to be a big pain to maintain +20 app targets. Imagine having to change something in all of the Info.plists or add a new dependency from Carthage manually for all apps at the same time 🤯 Now we can just change it in a single place and next time we generate the project it’s reflected for all the apps.</p>
<h3 id="what’s-the-feature-that-you-like-the-most-from-tuist-and-why?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s the feature that you like the most from Tuist and why?<a href="#what’s-the-feature-that-you-like-the-most-from-tuist-and-why?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s the feature that you like the most from Tuist and why?"></a></h3>
<p>
There are so many nice features in Tuist already but I think the <a href="https://docs.old.tuist.io/guides/helpers/">project description helpers</a> are my favorite. It allows us to generalize and reuse the way an app or framework is configured.</p>
<h3 id="do-you-use-project-description-helpers?-if-so,-how?-would-you-mind-adding-a-code-snippet-that-illustrates-your-usage." tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use project description helpers? If so, how? Would you mind adding a code snippet that illustrates your usage.<a href="#do-you-use-project-description-helpers?-if-so,-how?-would-you-mind-adding-a-code-snippet-that-illustrates-your-usage." class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use project description helpers? If so, how? Would you mind adding a code snippet that illustrates your usage."></a></h3>
<p>
We use project description helpers for everything from small utilities to defining a full app target. It’s a nice way to make sure that all our white-label apps and frameworks are configured in the exact same way. Here comes a few examples:</p>
<p>
<strong>Shorthand for defining Carthage dependencies</strong></p>
<p>
To avoid having to repeat the path to the Carthage build folder we have defined an extension on the TargetDependency type to make it possible to define the dependency with just the name.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
extension TargetDependency {
    public static func carthage(_ name: String) -&gt; TargetDependency {
        .framework(path: .init(&quot;../Carthage/Build/iOS/\(name).framework&quot;))
    }
}    </shiki-highlight>
  </div>
</div>
<p>
<strong>Specifying the app project</strong></p>
<p>
In our project description helpers we have defined a <em>&quot;Customer&quot;</em> struct to specify a customer/app in our white-label project. We then have extensions on the Target type to set up an app and UI test target from a customer instance. Our <code class="inline">Project.swift</code> for the app project then looks like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let customers: [Customer] = [
    .init(
        name: &quot;Customer #1&quot;,
        bundleId: &quot;app.emplate.customer1&quot;,
        fbAppId: &quot;12345678&quot;
    ),
    .init(
        name: &quot;Customer #2&quot;,
        bundleId: &quot;app.emplate.customer2&quot;,
        fbAppId: &quot;87654321&quot;
    ),
]

let project = Project(
    name: &quot;EmplateConsumer&quot;,
    targets: customers.flatMap { [.app($0), .uiTest($0)] }

)    </shiki-highlight>
  </div>
</div>
<h3 id="one-more-thing:-if-you-started-the-project-again,-what-would-you-do-differently?" tabindex="-1" class="marketing__blog_post__body__content__heading">
One more thing: If you started the project again, what would you do differently?<a href="#one-more-thing:-if-you-started-the-project-again,-what-would-you-do-differently?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to One more thing: If you started the project again, what would you do differently?"></a></h3>
<p>
Never promise support for anything below iOS 13 and use SwiftUI for all our UI code 😃</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with Kamil Pyć - With Bazel we were able to reduce build times by 70% on clean builds ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this interview, we talk with Kamil Pyć, Senior Mobile Developer at Allegro. Allegro is one of the few companies that have undertaken replacing Xcode's build system with Bazel, and that led them to an improvement in build times of roughly 95%. In this interview, Kamil shares more about Bazel's adoption, and some other insights about their project and teams. ]]></summary>
      <link href="https://tuist.dev/blog/2020/06/22/kamil"/>
      <id>https://tuist.dev/blog/2020/06/22/kamil</id>
      <updated>Mon, 22 Jun 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
When we announced the idea of publishing a series of interviews around app development at scale Kamil offered to participate and tell us more about iOS development in the biggest e-commerce company in Poland, <a href="https://allegro.pl">Allegro</a></p>
<h3 id="tell-us-more-about-yourself-and-the-project-you-work-on" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tell us more about yourself and the project you work on<a href="#tell-us-more-about-yourself-and-the-project-you-work-on" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tell us more about yourself and the project you work on"></a></h3>
<p>
I&#39;m Kamil Pyć. I have been working as a Senior Mobile Developer at <a href="https://allegro.pl">Allegro</a> for over 6 years. Currently I am part of the team responsible for supporting other developers - providing tooling and solutions for them to create our app fast and efficiently. Allegro is Poland&#39;s biggest e-commerce company - providing millions of products to millions of customers. That was a succulent offer that we couldn&#39;t turn down so let&#39;s dive right into the interview with Kamil:</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many engineers work on features and how many take care of the infrastructure of your projects?<a href="#how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many engineers work on features and how many take care of the infrastructure of your projects?"></a></h3>
<p>
We used to have platform specific teams but now mobile developers are part of feature teams. Currently we have about <strong>35 developers</strong> working on our iOS application. Our app is divided into <strong>50 modules</strong> so every team has at least one module to take care of. We have a dedicated team that performs releases every two weeks and our iOS infrastructure is a team of three people.</p>
<h2 id="project-and-code-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project and code architecture<a href="#project-and-code-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project and code architecture"></a></h2>
<h3 id="what-are-the-main-challenges-on-your-architecture-when-scaling?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are the main challenges on your architecture when scaling?<a href="#what-are-the-main-challenges-on-your-architecture-when-scaling?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are the main challenges on your architecture when scaling?"></a></h3>
<p>
There is nothing revolutionary about our code architecture - we mostly use MVVM, yet we are open to other paradigms if they are more suitable for the use case at hand. For example reactive programming architecture is applied just in the module of user registration which has a lot of input and validation.</p>
<p>
Main challenge of working with application that have many modules and over 500k+ lines of code is how to work at such a scale. If we have like hundreds of modules described with yamls and for some reason we would like to change all of them, sometimes it is just easier to write a script to do it. With many developers it’s hard to track all changes in codebase, that why we have added many automated metrics like clean &amp; warmbuild times, application size &amp; launch time etc.
We managed to solve a couple of problems we had with a large code base - long compilation time is fixed thanks to <a href="https://bazel.build/">Bazel</a> caching and we used to have many conflicts in Xcode projects - thanks to XcodeGen we don’t have to worry about that.
We work in iOS monorepo, all of our modules and applications are in one repository so sharing frameworks is as easy as adding one line into the XcodeGen project spec.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<h3 id="what’s-your-take-on-external-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your take on external dependencies?<a href="#what’s-your-take-on-external-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your take on external dependencies?"></a></h3>
<p>
We use cocoapods but the standard way of integration is not scaling well. To avoid conflict in Pod projects and to avoid adding all modules into Podfile we set <code class="inline">integrate_targets: false, generate_multiple_pod_projects: true</code>. Thanks to that our dependencies look and behave just like our internal modules and we can easily add them to any project.
We keep the number of external dependencies as low as possible, few essentials we use are <a href="https://github.com/SDWebImage/SDWebImage">SDWebImage</a> for downloading images or <a href="https://firebase.google.com/">Firebase</a> for collecting crash reports. When we integrate a third party dependency we always create a wrapper for it so it’s easy for us to replace it or remove it since it’s imported only in one place.</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?<a href="#how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?"></a></h3>
<p>
We follow <a href="https://martinfowler.com/articles/practical-test-pyramid.html">The Practical Test Pyramid</a>, we are getting closer to <strong>20k unit tests</strong>, we have a couple of test suites for UI tests - fast general one with critical buying paths that are built with every PR and a couple more detailed that are scheduled and another set that runs on real devices. We used <a href="https://github.com/pointfreeco/swift-snapshot-testing">snapshot testing</a> for visual regression and <a href="https://github.com/google/EarlGrey">EarlGrey</a> for UI testing.</p>
<h2 id="tooling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tooling<a href="#tooling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tooling"></a></h2>
<h3 id="what-are-some-challenges-you-are-facing-scaling-up-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are some challenges you are facing scaling up your project?<a href="#what-are-some-challenges-you-are-facing-scaling-up-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are some challenges you are facing scaling up your project?"></a></h3>
<p>
The with tooling is that the only way to know that someone has a problem with tools is to report it to you with email or Slack. That&#39;s why we have created a wrapper master tool for our tool that provide us with that - we now know how long it takes for XcodeGen to generate our project, if there were any errors - thanks to that we have more control over tools we use, if any tool update will increase error rate or execution time - we will know before anyone will report it to use. Looks like Bazel is most popular tool in iOS world that you can achieve just that - it’s used by teams in <a href="https://www.lyft.com/">Lyft</a>, <a href="https://www.pinterest.com/">Pinterest</a>, <a href="https://www.linkedin.com/feed/">LinkedIn</a> and a few other large mobile teams.</p>
<h2 id="build-times" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build times<a href="#build-times" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build times"></a></h2>
<h3 id="what-was-the-biggest-challenge-of-adopting-bazel?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What was the biggest challenge of adopting Bazel?<a href="#what-was-the-biggest-challenge-of-adopting-bazel?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What was the biggest challenge of adopting Bazel?"></a></h3>
<p>
Our motivation to use Bazel was looking for a way to reduce our build time. Tweaking build settings and hunting Swift compiler with -Xfrontend is a short time solution that gains us ~5% of build time drop. Only sensible way to seriously improve build time is to not build anything that was already built in the past - just download it from a shared cache.
At the beginning we tried integrating Bazel using official rules for iOS, but that way had many issues:</p>
<ul>
  <li>
Wwe couldn&#39;t mix Obj-c and Swift in single module  </li>
  <li>
We would have to migrated and maintain BUILD files for 3rd party dependencies  </li>
  <li>
It’s impossible to do incremental adoption - so we would have to migrated all of our modules at once  </li>
  <li>
Build is performed outside of Xcode, so to debug or profile the app we would have to generate special project that would allow as to do it, official tool for that - <a href="https://github.com/bazelbuild/tulsi">Tulsi</a> don’t do it quite well, probably we would have to build our own tool like Pinterests did with <a href="https://github.com/pinterest/xchammer">XCHammer</a>.  </li>
</ul>
<p>
During the Bazel evaluation we did find it pretty flexible - we can basically cache anything that takes input files and generate output. We added a pretty simple xcodebuild wrapper in Starlak <em>(language used by Bazel)</em> and we were able to generate cacheable XCFrameworks for our modules using good old Xcode and .xcodeproj. Later we had to migrate to fat frameworks because of problems that began to surface with XCFrameworks.</p>
<p>
We have a special focusing tool similar to <code class="inline">tuist focus</code> - developers select modules to focus on and only those are included in the workspace, everythings else is built with Bazel as build phase and copied to <code class="inline">BUILT_PRODUCTS_DIR</code>.</p>
<p>
<em>So how much did the build time improve?</em> Our dependencies are responsible for about ~70% of build time and we were able to <strong>reduce by 95% on clean build</strong> -remaining 5% is the time to download a cache from the server and copy it build dir. Our next goal is to cache the application the same way as we do for modules and reduce this time even further.</p>
<h2 id="wwdc" tabindex="-1" class="marketing__blog_post__body__content__heading">
WWDC<a href="#wwdc" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to WWDC"></a></h2>
<h3 id="what-are-you-the-most-excited-about-for-wwdc?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are you the most excited about for WWDC?<a href="#what-are-you-the-most-excited-about-for-wwdc?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are you the most excited about for WWDC?"></a></h3>
<p>
I wouldn&#39;t change much if I start the project again - probably just to use Combine and SwiftUI - because we still support iOS 12 users and we are not able to use all the new goodies right away.
For this year&#39;s WWDC I am most excited about changes in Xcode - some stuff are already in progress - like <a href="https://github.com/apple/swift-llbuild2">llbuild2</a> - it’s a change that we can get native Bazel like solution.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with Donal O'Brien - We measure developer build times so that we can measure improvements and regressions ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this interview, we talk with Donal O'Brien from the core clients team at SoundCloud. He shares how they leveraged modularization, Tuist, and tools like Sourcery to overcome the challenges they faced while scaling the app. Moreover, he touches on some present challenges like developer awareness and the maintenance of the tools around the project. ]]></summary>
      <link href="https://tuist.dev/blog/2020/06/18/donal"/>
      <id>https://tuist.dev/blog/2020/06/18/donal</id>
      <updated>Thu, 18 Jun 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
This week we are interviewing Donal. He&#39;s currently part of the core clients team at <a href="https://soundcloud.com">SoundCloud</a> where his role is to provide support for their engineers to be productive in their day to day work. The motivation for building Tuist came from the challenges SoundCloud was facing so we are pleased to have Donal sharing more about them in his interview.</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="how-are-teams-structured-at-soundcloud?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How are teams structured at SoundCloud?<a href="#how-are-teams-structured-at-soundcloud?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How are teams structured at SoundCloud?"></a></h3>
<p>
Teams are typically structured in a cross disciplinary fashion with a well defined focus on some particular part of the business, e.g. listeners, creators, ads, growth etc. There are typically a mix of engineers from different disciplines, e.g. there might be two iOS, two Android and two backend on a single team. Of course, most teams also have an engineering manager, product manager and design / UX representative.</p>
<h3 id="how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many engineers work on features and how many take care of the infrastructure of your projects?<a href="#how-many-engineers-work-on-features-and-how-many-take-care-of-the-infrastructure-of-your-projects?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many engineers work on features and how many take care of the infrastructure of your projects?"></a></h3>
<p>
There are currently <strong>16 iOS engineers</strong> working on features and two dedicated to infrastructure / tooling, i.e. the Core Clients engineers.</p>
<h2 id="project-and-code-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project and code architecture<a href="#project-and-code-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project and code architecture"></a></h2>
<h3 id="could-you-describe-the-architecture-of-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Could you describe the architecture of your project?<a href="#could-you-describe-the-architecture-of-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Could you describe the architecture of your project?"></a></h3>
<p>
The project was originally a monolith, which was gradually migrated to a modularised setup over a few years. We still have quite a lot of code in the main app but most developers no longer need to touch this part on a frequent basis.</p>
<p>
There are currently <strong>27 modules / subprojects</strong>, which are dedicated to some business concerns in particular (e.g. <code class="inline">Ads</code> or <code class="inline">Discovery</code>). Most of these modules actually expose more than one framework. Some of these additional frameworks are used for testing, e.g. in order to share mocks with other parts of the codebase and some are used to run “example apps” that enable developers to work on features without the compile times of the main app.</p>
<h3 id="what-code-paradigms-and-architectures-do-you-follow?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What code paradigms and architectures do you follow?<a href="#what-code-paradigms-and-architectures-do-you-follow?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What code paradigms and architectures do you follow?"></a></h3>
<p>
Typically new features are developed using clean architecture such as <a href="https://www.objc.io/issues/13-architecture/viper/">VIPER</a>.</p>
<h3 id="if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" tabindex="-1" class="marketing__blog_post__body__content__heading">
If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?<a href="#if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?"></a></h3>
<p>
We use some code generation techniques such as <a href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a> for mock and test data generation. There’s a central collection of user scripts that we commit to the app’s repo for all sorts of repetitive tasks such as generating feature flag code and running common commands.</p>
<h3 id="what-are-the-main-challenges-on-your-architecture-when-scaling?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are the main challenges on your architecture when scaling?<a href="#what-are-the-main-challenges-on-your-architecture-when-scaling?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are the main challenges on your architecture when scaling?"></a></h3>
<p>
Before Tuist there were some concerns around the length of time it would take to generate a new module. In certain circumstances this could take up to a few days. Also, with developers relying on relatively verbose and sometimes outdated documentation to create the frameworks, inevitable inconsistencies in project structure and settings emerged.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<h3 id="how-do-you-manage-your-third-party-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you manage your third-party dependencies?<a href="#how-do-you-manage-your-third-party-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you manage your third-party dependencies?"></a></h3>
<p>
Mainly <a href="https://cocoapods.org">CocoaPods</a> but also some <a href="https://github.com/carthage/carthage">Carthage</a>.</p>
<h3 id="what’s-a-third-party-dependency-your-project-heavily-depends-on?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s a third-party dependency your project heavily depends on?<a href="#what’s-a-third-party-dependency-your-project-heavily-depends-on?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s a third-party dependency your project heavily depends on?"></a></h3>
<p>
We don’t rely too heavily on any one external dependency but there are a few, which were introduced at the beginning and managed to spread throughout the codebase <em>(i.e. an early version of <a href="https://github.com/ReactiveCocoa/ReactiveCocoa">ReactiveCocoa</a> or the <a href="https://github.com/specta/specta">Specta</a> unit test framework)</em>. However, it’s highly discouraged to use these frameworks currently for some well documented reasons. In that way we no longer rely on them but it’s hard to get rid of them!</p>
<h3 id="what’s-your-take-on-external-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your take on external dependencies?<a href="#what’s-your-take-on-external-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your take on external dependencies?"></a></h3>
<p>
Generally I think a thorough cost / benefit analysis should be carried out before committing to any third party dependency that might lead to negative business impact in the future such as the emergence of app instability or lower developer productivity.</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
There’s a strong emphasis on unit testing, with a much lower number of UI tests.</p>
<h3 id="do-you-use-third-party-frameworks-for-testing?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use third-party frameworks for testing?<a href="#do-you-use-third-party-frameworks-for-testing?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use third-party frameworks for testing?"></a></h3>
<p>
Yes, but only for legacy reasons. Developers are now encouraged to use <a href="https://developer.apple.com/documentation/xctest">XCTest</a> directly, with the addition of some in-house conveniences on top.</p>
<h3 id="how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?<a href="#how-many-tests-do-you-have-and-how-are-they-split-between-unit/integration/ui.-which-ones-give-you-more-confidence?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How many tests do you have and how are they split between unit/integration/ui. Which ones give you more confidence?"></a></h3>
<p>
We currently have over <strong>16,000 unit tests</strong>. These are split roughly half and half between the modules and the main app. We have far fewer UI tests.</p>
<h2 id="tooling" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tooling<a href="#tooling" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tooling"></a></h2>
<h3 id="what-internal-tools-did-you-build-that-you-are-proud-of?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What internal tools did you build that you are proud of?<a href="#what-internal-tools-did-you-build-that-you-are-proud-of?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What internal tools did you build that you are proud of?"></a></h3>
<p>
Some tooling around code and framework generation using Sourcery and Tuist’s scaffold command are some things that come to mind.</p>
<h3 id="what-are-your-main-challenges-on-tooling-when-scaling?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are your main challenges on tooling when scaling?<a href="#what-are-your-main-challenges-on-tooling-when-scaling?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are your main challenges on tooling when scaling?"></a></h3>
<ul>
  <li>
<strong>Developer awareness:</strong> some developers are just unaware of the existence of tooling or correct usage. Documentation goes some way to alleviating this but discoverability / maintenance of this documentation can also be an issue.  </li>
  <li>
<strong>Maintenance:</strong> sometimes tooling goes flaky due to lack of love or the lack of a dedicated owner whose responsibility it is to maintain them.  </li>
  <li>
<strong>System inconsistencies:</strong> even though we use tools such as Bundler, sometimes some developers can experience issues that are hard to reproduce for others.  </li>
</ul>
<h3 id="what-are-some-challenges-you-are-facing-scaling-up-your-project?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are some challenges you are facing scaling up your project?<a href="#what-are-some-challenges-you-are-facing-scaling-up-your-project?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are some challenges you are facing scaling up your project?"></a></h3>
<p>
Deciding upon the correct hierarchical framework structure can be a tough call. Should you go with a single base layer to enable communication between frameworks or should there be multiple shared frameworks?</p>
<h2 id="build-times" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build times<a href="#build-times" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build times"></a></h2>
<h3 id="what’s-your-cold-start-build-time,-and-what-are-your-plans-to-improve-it" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your cold start build time, and what are your plans to improve it<a href="#what’s-your-cold-start-build-time,-and-what-are-your-plans-to-improve-it" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your cold start build time, and what are your plans to improve it"></a></h3>
<p>
A clean build can take up to seven or eight minutes. There are constant ideas and initiatives to monitor and improve build times. Firstly we measure developer build times so that we can measure improvements and regressions. However, we want to improve on this further. We intend to continue modularising the app by creating new modules and extracting functionality from the main app into other existing ones. We intend to implement tooling that can relieve some of the burden on developers during modularisation. We’re also interested in the potential of build artefact caching and having the ability to dynamically link frameworks in development but statically for release. We’ve also identified some optimisations that could be possible around some of the build phases of the app that we intend to tackle in the future.</p>
<h2 id="tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist<a href="#tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist"></a></h2>
<h3 id="what’s-the-feature-that-you-like-the-most-from-tuist-and-why?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s the feature that you like the most from Tuist and why?<a href="#what’s-the-feature-that-you-like-the-most-from-tuist-and-why?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s the feature that you like the most from Tuist and why?"></a></h3>
<p>
<code class="inline">tuist generate</code> 😃. Aside from that I also like the scaffold feature. We use that for templating new frameworks, which speeds things up quite a bit. I use tuist edit all the time to get code completion and all the other goodies that come with the IDE.</p>
<h3 id="do-you-use-project-description-helpers?-if-so,-how?" tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use project description helpers? If so, how?<a href="#do-you-use-project-description-helpers?-if-so,-how?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use project description helpers? If so, how?"></a></h3>
<p>
Yes, our entire setup is done using the <code class="inline">ProjectDescriptionHelpers</code>. In some cases, the manifest for a framework is <strong>a single line of code</strong> due to the use of <code class="inline">ProjectDescriptionHelpers</code>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Easily setup signing for your project with Tuist 1.11.0 Volare ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The new Tuist release 1.11.0 Volare introduces a signing feature to help you with maintaining and integrating your signing artifacts. ]]></summary>
      <link href="https://tuist.dev/blog/2020/06/17/version-1110"/>
      <id>https://tuist.dev/blog/2020/06/17/version-1110</id>
      <updated>Wed, 17 Jun 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hi! 👋</p>
<p>
I am really excited to write this blog post as we have a great new feature for you to use -
and this feature is signing 🔑</p>
<p>
So, let&#39;s dive right into it 🏊‍♂️</p>
<h2 id="signing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Signing<a href="#signing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Signing"></a></h2>
<p>
Signing is one of the most complicated domains that iOS developers
have to deal with in Xcode. And although Apple has introduced automatic signing feature,
most teams have decided not to use it as it creates a messy environment for their team.</p>
<p>
With the new feature, you&#39;ll be able to put your provisioning profiles and certificates
into <code class="inline">Tuist/Signing</code> directory and ... just run <code class="inline">tuist generate</code>. That&#39;s it!
No figuring out how to set up the Xcode build settings as that is done for you.
And as a plus your signing artifacts will be automatically encrypted with
your key at <code class="inline">master.key</code>, so you can safely push it to your remote
repository, so other team members can run the apps on a device, too ✨
You can find more info in the <a href="https://docs.old.tuist.io/commands/signing/">documentation</a></p>
<p>
You can also check out an introduction video where we
show you the feature in action:</p>
<p>
<a href="https://youtu.be/WGKp1EHcpME">https://youtu.be/WGKp1EHcpME</a></p>
<p>
Feel free to try it out and let us know your feedback! 🙂</p>
<p>
Note that we are also working hard on automating the process
of generating provisioning profiles and certificates for you. Stay tuned 👀</p>
<h2 id="build" tabindex="-1" class="marketing__blog_post__body__content__heading">
Build<a href="#build" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Build"></a></h2>
<p>
We are still continuing to work on <code class="inline">build</code> feature, thanks to <a href="https://github.com/pepicrft">@pepicrft</a>
it is now possible to run <code class="inline">tuist build --configuration Configuration</code> to specify the configuration you want to build.
There is more to come, so keep yourself updated 📝</p>
<h2 id="other-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other improvements<a href="#other-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other improvements"></a></h2>
<ul>
  <li>
Thanks to <a href="https://github.com/davidbrunow">@davidbrunow</a> there is now support for Watch architecture ⌚  </li>
</ul>
<h3 id="bug-fixes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug fixes<a href="#bug-fixes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug fixes"></a></h3>
<ul>
  <li>
Fix <code class="inline">tuist build</code> building a wrong workspace <a href="https://github.com/tuist/tuist/pull/1427">#1427</a> by <a href="https://github.com/fortmarek">@fortmarek</a>  </li>
  <li>
<code class="inline">tuist edit</code> always creates a project in a new temp dir <a href="https://github.com/tuist/tuist/pull/1424">#1424</a> by <a href="https://github.com/fortmarek">@fortmarek</a>  </li>
  <li>
Fix <code class="inline">tuist init</code> and <code class="inline">tuist scaffold</code> with new ArgumentParser version <a href="https://github.com/tuist/tuist/pull/1425">#1425</a> by <a href="https://github.com/fortmarek">@fortmarek</a>  </li>
  <li>
<code class="inline">--clean</code> argument ot the build command <a href="https://github.com/tuist/tuist/pull/1421">#1421</a> by <a href="https://github.com/pepicrft">@pepicrft</a>  </li>
</ul>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
To try out the new <code class="inline">signing</code> feature run <code class="inline">tuist update</code>.
We are also extremely happy to see more teams adopting tuist
as they are trying to achieve scalable projects
that are still joy to work on!</p>
<p>
Let us know your thoughts, ideas and experiences on <a href="https://community.tuist.io">our community forum</a> and <a href="https://slack.tuist.io">Slack group</a>,
we are always keen to make other voices heard in the community! 🙂</p>
<p>
Thanks for reading and stay safe.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Interview with Marek Fořt - The feature that I enjoy the most about Tuist is the clarity of manifest files ]]></title>
      
      
      <author>
        <name><![CDATA[ Tuist ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this interview, Marek shares his experience at AckeeCZ adopting the Microfeatures architecture and how they use Tuist to codify the structure of their projects. He also talks about his stance regarding the usage of third-party dependencies, as how they approach testing to deliver code fast and with confidence. ]]></summary>
      <link href="https://tuist.dev/blog/2020/06/11/marek"/>
      <id>https://tuist.dev/blog/2020/06/11/marek</id>
      <updated>Thu, 11 Jun 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
This post is the first one of a series of interviews about how different companies in the industry are doing app development at scale.
Our first interviewee is Marek Fořt, iOS developer at <a href="https://www.ackee.cz/en">AckeeCZ</a>, an app development studio based in the Czech republic.
Marek is a core member of Tuist, and has been the brain behind features like <a href="https://docs.old.tuist.io/commands/scaffold/">scaffolding</a>, and soon signing management.</p>
<p>
Let&#39;s dive right into Marek&#39;s experience doing app development at scale:</p>
<h2 id="team-structure" tabindex="-1" class="marketing__blog_post__body__content__heading">
Team structure<a href="#team-structure" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Team structure"></a></h2>
<h3 id="how-are-the-teams-structured?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How are the teams structured?<a href="#how-are-the-teams-structured?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How are the teams structured?"></a></h3>
<p>
We have a platform-oriented <em>(iOS, Android, web...)</em> teams structure - every team has a team leader who is the go-to person for the other members.</p>
<h2 id="project-and-code-architecture" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project and code architecture<a href="#project-and-code-architecture" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project and code architecture"></a></h2>
<h3 id="what-code-paradigms-and-architectures-do-you-follow?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What code paradigms and architectures do you follow?<a href="#what-code-paradigms-and-architectures-do-you-follow?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What code paradigms and architectures do you follow?"></a></h3>
<p>
We use MVVM architecture with <a href="https://github.com/ReactiveCocoa/ReactiveSwift">ReactiveSwift</a> for all of our projects currently, although we have also started experimenting with <a href="https://github.com/pointfreeco/swift-composable-architecture">Composable architecture</a> and Combine since we think that Redux-like approach might be a better option once we start using SwiftUI. Along with the MVVM architecture we have also started using <a href="https://docs.old.tuist.io/building-at-scale/microfeatures/">microfeatures</a> approach for one of our larger projects - this has had the benefit of better separation of concerns, faster build times, we have also introduced an example app for each individual feature which means it is extremely easy to concentrate on the task at hand. You can check out our <a href="https://github.com/AckeeCZ/iOS-MVVM-ProjectTemplate/">MVVM template</a>: we are planning to publish a revamped version with the microfeatures and composable architecture approaches.</p>
<h3 id="if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" tabindex="-1" class="marketing__blog_post__body__content__heading">
If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?<a href="#if-you-have-multiple-apps,-how-do-you-share-code-between-them-and-how-do-you-use-internal-tools-to-automate-repetitive-processes?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to If you have multiple apps, how do you share code between them and how do you use internal tools to automate repetitive processes?"></a></h3>
<p>
Most of our shared codebase lives in our <a href="https://github.com/orgs/AckeeCZ/teams/ios/repositories">open-source repositories</a> - I’d highlight <a href="https://github.com/AckeeCZ/ACKategories">ACKategories</a> where our more general-purpose extensions and convenience structs and classes live and then <a href="https://github.com/AckeeCZ/ACKLocalization">ACKLocalization</a> which we use constantly to download and generate new localization strings from a Google spreadsheet. For building, testing and publishing an app we mostly use <a href="https://fastlane.tools">Fastlane</a>, but we are stoked about trying out new features in Tuist that could help us simplify a hard-to-reason-about Fastfiles.</p>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<h3 id="how-do-you-manage-your-third-party-dependencies?" tabindex="-1" class="marketing__blog_post__body__content__heading">
How do you manage your third-party dependencies?<a href="#how-do-you-manage-your-third-party-dependencies?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How do you manage your third-party dependencies?"></a></h3>
<p>
In most of our projects we use <a href="https://github.com/carthage">Carthage</a> and <a href="https://cocoapods.org">Cocoapods</a>. For Carthage we also use <a href="https://github.com/tmspzz/Rome/">Rome</a>, so not every user is forced to rebuild Carthage dependencies whenever they start working on a new project. But for our microfeatures app we have ditched Cocoapods and started using Swift Package Manager - managing a microfeatures architecture with Cocoapods was not ideal since there was an added overhead. But SPM dependencies are defined right in the Tuist manifests, so the definition and maintenance of dependencies is easier and helps with the code review process!</p>
<h2 id="testing" tabindex="-1" class="marketing__blog_post__body__content__heading">
Testing<a href="#testing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Testing"></a></h2>
<h3 id="what’s-your-testing-strategy?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s your testing strategy?<a href="#what’s-your-testing-strategy?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s your testing strategy?"></a></h3>
<p>
Since most of our logic lives in ViewModels and accompanying services, that’s where our focus lies when it comes to testing. We think testing is important, but on the other hand we do not strive to have a 100 % testing coverage. We let developers decide what they think are the important parts of code to test, so they gain confidence in the code they have written. It’s then part of the code review process to let the reviewer assess if the merge request has tests for the important business logic.</p>
<h2 id="tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Tuist<a href="#tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Tuist"></a></h2>
<h3 id="what-led-you-to-adopt-tuist?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What led you to adopt Tuist?<a href="#what-led-you-to-adopt-tuist?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What led you to adopt Tuist?"></a></h3>
<p>
The main reason for us, initially, was getting rid of merge conflicts due to changes in a <code class="inline">.pbxproj</code> file. Besides that we also wanted to have a better sense of changes in the xcode project since reading <code class="inline">.pbxproj</code> during the code review process was … let’s say not ideal. After leveraging Tuist for code generation we have started to looking into how to use it for further optimization of development process, like migrating to microfeatures architecture.</p>
<h4 id="what’s-the-feature-that-you-like-the-most-from-tuist-and-why?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s the feature that you like the most from Tuist and why?<a href="#what’s-the-feature-that-you-like-the-most-from-tuist-and-why?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s the feature that you like the most from Tuist and why?"></a></h4>
<p>
It’s very hard to pick one, but I think the feature that I enjoy the most about Tuist is the clarity of manifest files. Being able to define the architecture, modules, dependencies, etc. in Swift files is powerful and brings more joy to parts of development that have been error-prone and tedious before we started using Tuist.</p>
<h3 id="do-you-use-project-description-helpers?-if-so,-how?-would-you-mind-adding-a-code-snippet-that-illustrates-your-usage." tabindex="-1" class="marketing__blog_post__body__content__heading">
Do you use project description helpers? If so, how? Would you mind adding a code snippet that illustrates your usage.<a href="#do-you-use-project-description-helpers?-if-so,-how?-would-you-mind-adding-a-code-snippet-that-illustrates-your-usage." class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Do you use project description helpers? If so, how? Would you mind adding a code snippet that illustrates your usage."></a></h3>
<p>
We use project description helpers extensively and it’s a key to achieve readable and scalable manifest files as it lets you to define your projects in multiple files. This also means that it is possible to reuse parts of project definition and you can articulate your own interface for a new module or app, so you only need to focus on things that are specific to the domain you are working on. As an example, we have a set of custom configurations that come with a custom set of settings. With project description helpers they are defined for the developer with a custom enum called <code class="inline">AppCustomConfiguration</code>. You can see <a href="https://github.com/AckeeCZ/iOS-MVVM-ProjectTemplate/blob/master/Tuist/ProjectDescriptionHelpers/Project%2BTemplates.swift#L5">here</a> how easy it is to then use it for an app the developer is working on.</p>
<h2 id="other" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other<a href="#other" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other"></a></h2>
<h3 id="what-are-you-the-most-excited-about-for-wwdc?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What are you the most excited about for WWDC?<a href="#what-are-you-the-most-excited-about-for-wwdc?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What are you the most excited about for WWDC?"></a></h3>
<p>
I hope that Apple will bring a next iteration of SwiftUI which will be focused on stability, so it will be usable in production apps without having to deal with all the quirks and bugs the current releases have been plagued with. I love the declarative approach and, as tuist, it helps developers to focus on building, rather than being forced to write boilerplate code and deal with very complex systems that UIKit and Xcode projects definitely are.</p>
<h2 id="closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Closing words<a href="#closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Closing words"></a></h2>
<p>
Hopefully, this interview has brought you, the reader, some useful information about how tuist might fit into your team’s workflow. I can’t recommend Tuist enough and I am looking forward to seeing how new features might help with our work even further. At the moment we are trying out the new <code class="inline">build</code> command and I am also trying to work on a new signing feature that will make setting up app’s signing more deterministic and easy to use 🎉</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Building your projects with Tuist 1.10.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ This blog post introduces the latest version of Tuist, 1.10 Alma, that starts making projects the source of truth for automation too by providing a standard command, "tuist build", for building projects. ]]></summary>
      <link href="https://tuist.dev/blog/2020/06/04/version-1100"/>
      <id>https://tuist.dev/blog/2020/06/04/version-1100</id>
      <updated>Thu, 04 Jun 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
This week’s release is a bit special because we are shipping a feature that we’ve had in the backlog for a long time; we are expanding Tuist’s convenience to automation by providing a new command: <code class="inline">tuist build</code>.</p>
<h2 id="programmable-dsls" tabindex="-1" class="marketing__blog_post__body__content__heading">
Programmable DSLs<a href="#programmable-dsls" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Programmable DSLs"></a></h2>
<p>
Traditionally, teams have resorted to tools programmable DSL and scripts to expose a CLI interface to interact with their projects.
Fastfiles act as a translation between developers’ intents,
and the actual commands that materialize them.
The problem with this approach is that most teams end up with a non-consistent, non-deterministic, and complex automation flows, with a lot of duplicated code across files.</p>
<h2 id="making-the-manifest-files-the-source-of-truth" tabindex="-1" class="marketing__blog_post__body__content__heading">
Making the manifest files the source of truth<a href="#making-the-manifest-files-the-source-of-truth" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Making the manifest files the source of truth"></a></h2>
<p>
What are we doing differently? Rather than giving developers a DSL where they can define all different flavors of workflows,
we <strong>derive a set of standard commands from their projects defined in manifest files.</strong></p>
<p>
Tuist owns those commands and ensures that they work fast and deterministically.
Moreover,
since we are responsible for the generation of projects as well as the logic of those commands,
we can introduce optimizations without you having to do anything on your end; It’s like having a tooling team codified into a tool.</p>
<p>
Since the commands are standard, developers can familiarize themselves with them, and use them in any project defined with Tuist.
The commands are designed to be used with zero arguments. That means that users will be able to run the command without passing any arguments.
If you are familiar with <code class="inline">xcodebuild</code>,
you probably know that there are some required arguments and that you cannot compile your projects without them.
Users can run <code class="inline">tuist build</code>,
and the projects will compile.
Tuist infers default values to <strong>provide the best experience to the users</strong>.</p>
<h2 id="building-your-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Building your projects<a href="#building-your-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Building your projects"></a></h2>
<p>
The first automation command that we are shipping with this release is <code class="inline">tuist build</code>.
When used in a directory that contains a <code class="inline">Project.swift</code> or a <code class="inline">Workspace.swift</code>, it builds all buildable schemes of non-transitive projects (i.e., the projects in the current directory).</p>
<p>
Build also supports indicating the scheme that you’d like to build:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist build MyApp    </shiki-highlight>
  </div>
</div>
<p>
Since Tuist auto-generates schemes for your targets (default behavior), you can use the name of the target.</p>
<h2 id="feedback" tabindex="-1" class="marketing__blog_post__body__content__heading">
Feedback<a href="#feedback" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Feedback"></a></h2>
<p>
We are exploring a new dimension in Tuist,
so your feedback is precious to make sure we provide the best automation experience to users. If you are already using Tuist, you can run <code class="inline">tuist update</code> and then <code class="inline">tuist build</code> in any of your projects. Alternatively, you can clone the <a href="https://github.com/tuist/microfeatures-example">Microfeatures repository</a> and try to use the command there.</p>
<p>
You can answer to <a href="https://community.tuist.io/t/feedback-about-the-build-command/63">this topic</a> on our community forum with ideas, bugs, and concerns that you might have.</p>
<h2 id="what’s-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next<a href="#what’s-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next"></a></h2>
<p>
While users try this out and we collect feedback from them,
we’ll focus on implementing <code class="inline">tuist test</code> and <code class="inline">tuist run</code>.
The latter will allow developers to compile and run the apps from their terminals.
Who knows, maybe at some point developers can work on their projects without opening Xcode at all 🤷‍♀️.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.9.0 - Speedy Gonzales ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we announce the latest version of Tuist, 1.9.0, which introduces significant improvements in the performance of the project generation. ]]></summary>
      <link href="https://tuist.dev/blog/2020/05/29/version-190-speedy-gonzales"/>
      <id>https://tuist.dev/blog/2020/05/29/version-190-speedy-gonzales</id>
      <updated>Fri, 29 May 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hi there 👋,</p>
<p>
It has been quiet for the past few weeks,
but we are back to announce a new release that we just baked,
Tuist 1.9.0.
As you might have noticed,
from this release,
we started giving them names.
We not only do it for fun,
but we think it is easier to remember a release.</p>
<h2 id="faster-project-generation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Faster project generation<a href="#faster-project-generation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Faster project generation"></a></h2>
<p>
1.9.0&#39;s name is Speedy Gonzales,
which relates well with one of the most significant improvements with are shipping with this release:
<strong>faster project generation.</strong></p>
<p>
One of the features that make Tuist&#39;s project generation unique at scale is using Swift as a format for the manifest files.
That allows developers to edit their projects using Xcode,
where they can get auto-completion, documentation, and validations.
Moreover,
they can extract pieces of their manifest into a separate framework,
<code class="inline">ProjectDescriptionHelpers</code>,
which they can import and use from their manifest files.
That&#39;s great,
but it comes with costs.
One of those is having to compile the files,
which takes significantly longer than reading a YAML or JSON file from disk.
<a href="https://github.com/kwridan">Kas</a> noticed that and ventured into improving that.</p>
<p>
The result of this work is a project generation that is <strong>approximately 50% faster</strong>.
Insane.
We <a href="https://github.com/tuist/tuist/pull/1341">achieved</a> that by introducing caching.
After the manifest is first compiled,
we serialize it and store it as a JSON in the cache.
To uniquely identify the manifest in the cache,
we hash the content of the manifest as well as other files and metadata the manifest depends on,
for example,
the project description helpers.
If nothing has changed,
future project generations will read the JSON instead of using the compiler.</p>
<p>
And this is just the beginning.
While doing this work,
we spotted some other opportunities for improving performance.
One of them is loading the dependency graph concurrently using multiple threads.
Stay tuned because you&#39;ll hear more about this topic in future updates.</p>
<blockquote>
  <p>
Note that the new caching behavior is enabled by default.
If you notice project generation misbehaving, you can disable it by setting the environment variable <code class="inline">TUIST_CACHE_MANIFESTS=0</code>.  </p>
</blockquote>
<h2 id="other-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other improvements<a href="#other-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other improvements"></a></h2>
<p>
Besides making Tuist faster,
this release also <a href="https://github.com/tuist/tuist/pull/1382">adds support</a> for enabling the main thread checker in schemes.
It used to be enabled by default and we changed the behavior to be an opt-in feature.
If you define your own schemes,
<code class="inline">RunAction</code> and <code class="inline">TestAction</code> have now a new attribute,
<code class="inline">diagnosticsOptions</code> that you can use to enable the main thread checker:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let runAction = RunAction(config: .debug,
                          executable: targetReference,
                          diagnosticsOptions: [.mainThreadChecker])    </shiki-highlight>
  </div>
</div>
<p>
Moreover,
we continued working on the Cloud set of features,
adding some <a href="https://github.com/tuist/tuist/pull/1335">internal building blocks</a> that will be necesary for collecting insights from your builds,
and sending them to a server-side application that processes them.</p>
<h2 id="minor-bug-fixes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Minor bug fixes<a href="#minor-bug-fixes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Minor bug fixes"></a></h2>
<p>
Tuist 1.9.0 also <a href="https://github.com/Shopify/react-native/pull/1650">fixes a bug</a> that caused <code class="inline">tuist edit</code> not to wait while the project was being edited.
and <a href="https://github.com/tuist/tuist/pull/1361">removes</a> the unnecessary <code class="inline">CFBundleExecutable</code> attribute from the auto-generated <code class="inline">Info.plist</code> for bundle targets.</p>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
We are working on the following areas:</p>
<ul>
  <li>
We are close to have a first iteration of our <a href="https://github.com/tuist/tuist/pull/1066">support for configuring the environment and the generated projects for signing</a>.  </li>
  <li>
We are doing some technical-debt work turning our graph representation into a value type with the goal of minimizing side effects to make the project generation more deterministic.  </li>
  <li>
We&#39;ll continue building the client-side logic for the 2 major cloud features, insights and caching.  </li>
</ul>
<h2 id="some-closing-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Some closing words<a href="#some-closing-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Some closing words"></a></h2>
<p>
As always,
you can update Tuist by simply running <code class="inline">tuist update</code>.
We are excited to keep pushing the project forward and making interacting with your projects as easy and fun as possible.</p>
<p>
If you want to chat with contributors and other users of Tuist,
you can join our <a href="https://community.tuist.io">community forum</a>.
Also, you may consider supporting us on the <a href="https://github.com/sponsors/tuist">GitHub Sponsors</a> program and <a href="https://opencollective.com/tuistapp">Open Collective</a>.
This project is developed by people devoting their spare time,
so a token of appreciation means a lot.</p>
<p>
I hope you are all safe and wish you all a steady return to the new normal.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Dynamically generating Xcode projects ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post I talk about how Xcode's determinism and speed relates to the static nature of Xcode projects, and how Tuist leverages dynamism to help teams overcome the challenges of scaling up projects. ]]></summary>
      <link href="https://tuist.dev/blog/2020/05/26/dynamism"/>
      <id>https://tuist.dev/blog/2020/05/26/dynamism</id>
      <updated>Tue, 26 May 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
I’ve been thinking a lot lately about the static nature of Xcode projects.
I think it’s a design decision that makes Xcode behave <strong>fast and deterministically</strong>,
at least if the project is reasonably small.
In Android land,
things are dynamic.
<a href="https://gradle.org/">Gradle</a> has a loading phase where all the tasks are evaluated, and only then can you build and run your apps.</p>
<p>
Personally, <strong>I think the dynamic approach at scale is terrible</strong>. If the project is considerably large, it might take long and a lot of CPU power for Gradle to become responsive. The matter gets worse if we use tasks with side effects that might cause Gradle to yield different results in different environments.</p>
<p>
For that reason,
if I were Apple, I would keep Xcode projects as static as possible. With Xcode 11,
they <a href="https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app">added support</a> for the Swift Package Manager,
which,
as you might have noticed,
added a bit of dynamism to resolve the packages at launch time.</p>
<p>
Apple could introduce more subtle touches of dynamism to ease the maintenance of projects and minimize the likelihood of getting Git conflicts.
For example, the files that are part of a project could be defined using glob patterns like <code class="inline">Sources/**.swift</code>,
or even better,
following a convention for the directory structure like Android does.
They could be resolved at launch time like they are currently doing with Swift packages.</p>
<p>
At this point, you may wonder how Tuist relates to this dynamism I&#39;m talking about:
<strong>Tuist brings dynamism through project generation to help teams overcome the challenges of scaling up projects.</strong></p>
<p>
Here are some examples of things that we were able to provide by leveraging the dynamism of project generation:</p>
<ul>
  <li>
Having consistency across projects and targets by leveraging <a href="https://docs.old.tuist.io/guides/helpers/">project description helpers</a>.  </li>
  <li>
<a href="https://docs.old.tuist.io/guides/dependencies">Defining dependencies</a> explicitly with a simple and unified DSL.  </li>
  <li>
<a href="https://docs.old.tuist.io/commands/up/">Setting up</a> the environment deterministically to ensure Xcode behaviors and builds are reproducible.  </li>
  <li>
Throw errors early when projects have invalid configurations.  </li>
  <li>
Generating a <a href="https:://docs.old.tuist.io/commands/graph/">visual dependency tree</a> to have an overview of the project.  </li>
</ul>
<p>
And we are not done yet. We are streamlining more workflows like configuring the environment and the projects for signing and providing a standard CLI without having to mess around with script files or configure a Ruby environment properly.</p>
<p>
Like <a href="https://rubyonrails.org/">Rails</a> does in the Ruby community,
we are designing Tuist to spark joy when interacting with Xcode projects.
Over the past years,
we have seen a good amount of tools to help teams with all the different challenges that they face.
That&#39;s awesome,
but when combined together around Xcode projects,
teams end up with workflows that don&#39;t play well with each other and layers of indirection that add complexity and make the projects hard to reason about.</p>
<p>
Here are some concrete examples to illustrate the above:</p>
<ul>
  <li>
Inconsistent <a href="https://github.com/realm/SwiftLint">Swiftlint</a> errors because <a href="https://brew.sh">Homebrew</a> installed different versions of Swiftlint.  </li>
  <li>
Fastlane lanes printing errors but exiting with a exit status 0.  </li>
  <li>
Xcode failing to sign the app because a developer changed one of the signing build settings by mistake and no one spot it in a large <code class="inline">project.pbxproj</code> diff.  </li>
  <li>
Invalid dependencies configuration that results in some artifacts being copied into the final product and then causing release validations to fail.  </li>
  <li>
Developers getting different results when running Fastlane because they are not familiar with setting up Ruby environments and end up running the global Fastlane instead of the one pinned by <a href="https://bundler.io/">Bundler</a>.  </li>
  <li>
Adding a new framework to the dependency tree causes compilation issues on CI.  </li>
</ul>
<p>
Some teams might want to work in such a frustration-prone and complex environment.
It gives teams the freedom to customize every single bit of the way they work.
Still, it also leads them to waste time that they could otherwise spend building product features.
<strong>Tuist takes care of those things, ensuring that we provide a consistent and easy experience that sparks joy.</strong></p>
<p>
If you have been there and think it’s time to clean things up and make working with your project as enjoyable as it used to be when you first created the project with Xcode,
you can check out our <a href="https://docs.old.tuist.io/tutorial/get-started/">Get Started</a> documentation.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.8.0 - Adding support for localized sources ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post I talk about the Tuist verion 1.8.0 and the improvements that come with it. One of those is being able to define localized sources in the targets. Moreover, we changed the way we read the Swift version to always read it from the environment. ]]></summary>
      <link href="https://tuist.dev/blog/2020/05/11/version-180"/>
      <id>https://tuist.dev/blog/2020/05/11/version-180</id>
      <updated>Mon, 11 May 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hola 👋!</p>
<p>
Despite our plan to release new versions every Friday,
we are doing things a bit different this time,
and we are releasing a new version on Monday.
In this blog post, I&#39;m <strong>introducing the version 1.8.0</strong> of Tuist.</p>
<p>
Unlike past releases that were packed with many features,
this is a tiny one with barely additions.
Nonetheless,
we are writing a blog post because we believe in the power of narrative as a means to convey the ideas behind it.</p>
<p>
Let&#39;s dive right into what has changed in 1.8.0.</p>
<h2 id="support-for-localized-sources" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support for localized sources<a href="#support-for-localized-sources" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support for localized sources"></a></h2>
<p>
<a href="https://github.com/Rag0n">@Rag0n</a> added support for localized resources.
Thanks to it, you can now add localized files with the extension <code class="inline">.indentdefinition</code>.
Before this change,
we were treating the directories with extensions <code class="inline">.lproj</code>,
which Xcode uses go group localized resources and sources,
as a normal directory.</p>
<h2 id="read-the-swift-version-from-the-environment" tabindex="-1" class="marketing__blog_post__body__content__heading">
Read the Swift version from the environment<a href="#read-the-swift-version-from-the-environment" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Read the Swift version from the environment"></a></h2>
<p>
There used to be a <a href="https://github.com/tuist/tuist/pull/1317">few places</a> in the codebase where we used a hardcoded version of Swift.
To prevent it from causing issues when the hardcoded version doesn&#39;t match the system one,
we changed the implementation to always read the Swift version from the system.</p>
<h2 id="community-forum" tabindex="-1" class="marketing__blog_post__body__content__heading">
Community forum<a href="#community-forum" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Community forum"></a></h2>
<p>
It&#39;s been a while since we have it,
but it might have gone unnoticed for users of Tuist.
A while ago,
we created a <a href="https://community.tuist.io">community forum</a> with the <strong>aim of encouraging long and asynchronous discussions</strong> and making them searchable and indexable by search engines like Google.
Slack,
the communication tool that we had been using since the inception of Tuist is great at real-time discussions but is not ideal when many important discussions are going on.</p>
<p>
We&#39;ll continue using Slack, but we&#39;ll encourage people to use the forum for certain discussions.
We&#39;ll also continue using <a href="https://github.com/tuist/tuist/issues">GitHub issues</a> to report bugs,
propose improvements and features, and share RFCs to get input from other contributors.</p>
<p>
Here are some ongoing discussions worth checking out:</p>
<ul>
  <li>
<a href="https://community.tuist.io/t/ideas-for-tuist/20/2">Ideas for Tuist</a>  </li>
  <li>
<a href="https://community.tuist.io/t/an-opinionated-version-of-tuist/40">An opinionated version of Tuist</a>  </li>
  <li>
<a href="https://community.tuist.io/t/designing-great-experiences/38">Designing great experiences</a>  </li>
  <li>
<a href="https://community.tuist.io/t/making-schemes-an-implementation-detail/30">Making schemes an implementation detail</a>  </li>
  <li>
<a href="https://community.tuist.io/t/list-of-deprecations-for-2-0/24">List of deprecations for 2.0</a>  </li>
</ul>
<h2 id="some-fixes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Some fixes<a href="#some-fixes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Some fixes"></a></h2>
<ul>
  <li>
Auto-generated <code class="inline">Info.plist</code> files for iOS apps no longer have the launch and main storyboards set - <a href="https://github.com/tuist/tuist/pull/1289">#1289</a>  </li>
  <li>
Fixed a <code class="inline">scaffold</code> example in the documentation - <a href="https://github.com/tuist/tuist/pull/1273">#1273</a>  </li>
  <li>
Fixed the <code class="inline">help</code> command that stopped working after a recent refactor - <a href="https://github.com/tuist/tuist/pull/1250">#1250</a>  </li>
</ul>
<h2 id="what's-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next<a href="#what's-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next"></a></h2>
<p>
There&#39;s an <a href="https://github.com/tuist/tuist/pull/1186">ongoing work</a> to add support for signing to Tuist.
In a nutshell, Tuist will take care of installing certificates, copying profiles, and setting the right build settings to your projects.
All you need to do is to place them in the <code class="inline">Tuist/Signing</code> directory and use a built-in command to encrypt them.</p>
<p>
Moreover, we paused the work on the cache to refactor one of our key pieces of the codebase, the <a href="https://github.com/tuist/tuist/blob/main/Sources/TuistCore/Graph/Graph.swift">graph</a>.
Since its creation,
the model has gone through several iterations and broadened its responsibilities.
We think it&#39;s now a good time to refactor it into a value type that will support well current and future features that we are planning for Tuist.</p>
<p>
As always,
remember that you can update Tuist easily by running:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist update    </shiki-highlight>
  </div>
</div>
<p>
Having said all of that,
I wish you all a great and safe week.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Why Tuist? ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post I share my thoughts on why I think Tuist is a good choice to scale up Xcode projects, and guide the reader through what I believe are key features to make that easy. ]]></summary>
      <link href="https://tuist.dev/blog/2020/04/28/why-tuist"/>
      <id>https://tuist.dev/blog/2020/04/28/why-tuist</id>
      <updated>Tue, 28 Apr 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
If you are considering the adoption of Tuist,
you might wonder <em>why</em> a project like yours should make such a move.
The idea of adding a new tool to your toolbox might sound intimidating ―
it certainly is.
But believe me,
this is one that you won&#39;t regret about.
Despite having done our best to convey the idea behind Tuist,
and why it&#39;s an important piece when scaling up projects,
I feel we lacked a good summary.</p>
<h2 id="make-your-projects-consistent-and-conventional" tabindex="-1" class="marketing__blog_post__body__content__heading">
Make your projects consistent and conventional<a href="#make-your-projects-consistent-and-conventional" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Make your projects consistent and conventional"></a></h2>
<p>
After bootstrapping new projects and targets in Xcode,
it&#39;s up to the developers to ensure that projects are consistently configured and structured.
Some developers might see that as something great,
but that comes with some downsides:</p>
<ul>
  <li>
It adds <strong>indirection</strong> for developers when jumping between projects: <em>How is this project structured compared to this other?</em> <em>Why is this target linking using build settings flags while the other one is using build phases?</em>  </li>
  <li>
Xcode&#39;s <strong>indexing and build system</strong> might not work as effectively because it needs to resolve configuration nuances across all the projects.
Moreover, those nuances might be conflicting and result in compilation errors.  </li>
</ul>
<p>
You might have seen teams solving this problem at the build settings level by extracting them into reusable <a href="https://nshipster.com/xcconfig/">Xcode Build Configuration Files</a>.
Still, we should not disregard that settings are just a piece of the cake ―
There are also build phases, targets, or schemes, for which Xcode doesn&#39;t provide any way to reuse them.
Other teams resort to scripts that run some checks on the projects,
but that results in a poor experience for developers because those checks are not built into their workflows.</p>
<p>
Tuist solves this by providing <a href="https://docs.old.tuist.io/guides/helpers/">project description helpers</a>.
All you need to do is to define what types of projects are supported,
and codify them into functions that return templated projects:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

// Projects+Template.swift

extension Project {
  static func featureFramework(name: String) -&gt; Project { /** Initialize project **/ }
  static func iOSApp(name: String) -&gt; Project { /** Initialize project **/ }
}    </shiki-highlight>
  </div>
</div>
<p>
That makes it possible to create a new feature framework that is consistent with the rest.
For instance,
I can create a new Search feature framework by creating a <code class="inline">Search</code> directory,
and placing the following <code class="inline">Project.swift</code> file in it:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.featureFramework(name: &quot;Search&quot;)    </shiki-highlight>
  </div>
</div>
<blockquote>
  <p>
Note how idiomatic and concise the definition of projects is ― your project is defined in one line.  </p>
</blockquote>
<h2 id="dependencies" tabindex="-1" class="marketing__blog_post__body__content__heading">
Dependencies<a href="#dependencies" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Dependencies"></a></h2>
<p>
If there&#39;s something that bothered me when using Xcode daily,
it was how hard it becomes to <strong>maintain a dependency graph</strong>.
At some point,
you extract some logic into a transitive framework.
After following a very manual process,
other projects fail to compile.
You probably forgot to embed that framework into some products that have it as a transitive dependency.</p>
<p>
I&#39;ve talked to developers that think that it&#39;s developers&#39; fault because they don&#39;t know how to do things in Xcode.
I&#39;d counter-argue that when the dependency graph is large,
<strong>there&#39;s so much they need to know to do things right</strong>,
that the process becomes not just very manual,
but error-prone.
Having this mindset often leads to a terrible bus factor.
There&#39;s a person in the team that did the initial work of creating projects and frameworks,
and what&#39;s often considered <em>&quot;the person that knows Xcode well&quot;.</em></p>
<p>
In Tuist,
we tasked ourselves with simplifying that until the point that <strong>anyone could add/remove dependencies easily</strong>.
We imagined how we&#39;d like the user interface to be, and we built the rest from there:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
public enum TargetDependency: Codable, Equatable {
  case target(name: String)
  case project(target: String, path: Path)
  case framework(path: Path)
  case library(path: Path, publicHeaders: Path, swiftModuleMap: Path?)
  case package(product: String)
  case sdk(name: String, status: SDKStatus)
  case cocoapods(path: Path)
  case xcFramework(path: Path)
}    </shiki-highlight>
  </div>
</div>
<p>
When people compare Tuist to YAML-based project generators,
the <strong>beauty of the dependencies API</strong> pops in my mind.
My answer is always that it really depends on what you want for your projects.
If you want to move away from <code class="inline">.pbxproj</code> files and describe things in simpler YAML files using the same Xcode&#39;s concepts and ideas,
YAML-based project generation is your friend.
However, if you want to work with simpler concepts and ideas, and be more conventional, Tuist is your tool.
Our principle is that <strong>simplicity and consistency are vital to scale up projects</strong>.</p>
<p>
Some well-known companies that adopted a YAML-approach for the generation of projects ended up building a tool on top of it.
While that&#39;s something large companies can do,
you might not want to find yourself in the situation where you need to build a tool yourself.
Moreover,
having tools on top of other tools adds indirections,
which in fact,
complicates optimization and debugging.</p>
<h2 id="catch-misconfiguration-errors-early" tabindex="-1" class="marketing__blog_post__body__content__heading">
Catch misconfiguration errors early<a href="#catch-misconfiguration-errors-early" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Catch misconfiguration errors early"></a></h2>
<p>
Xcode delegates catching errors to its build system.
The problem with that is that approach is that there are certain errors that the build system doesn’t know how to misconfigurations in the project. For example, if there’s a circular dependency, the compilation will fail with an error along the lines of: <code class="inline">“X not found”</code>. <em>What would you think as a developer?</em> <em>Is it not found because I didn’t configure the right search paths?</em> <em>Should I change the order in which targets are compiled in my scheme?</em> The last thing you’d probably think is that there’s a circular dependency.</p>
<p>
To prevent that, Tuist tries to catch errors as early as possible.
We know developers’ time is a precious asset,
and they should not spend it debugging Xcode errors unrelated to their changes.
We can’t catch everything, but we do our best.
Especially around the dependency graph.</p>
<p>
Thanks to it, any developer can add a new framework to the dependency graph with the confidence that if they are doing something wrong, Tuist will catch it. Isn’t that great? Let me repeat that again: <strong>anyone can modify the graph with confidence</strong>. I can’t stress enough how great that is to grow your projects. If you make something wrong, you know that <code class="inline">tuist generate</code> will tell you.</p>
<p>
In the entrepreneurial jargon, we&#39;d say that we are <strong>democratizing scaling up projects</strong>.</p>
<h2 id="and-more-yet-to-come..." tabindex="-1" class="marketing__blog_post__body__content__heading">
And more yet to come...<a href="#and-more-yet-to-come..." class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to And more yet to come..."></a></h2>
<p>
The benefit of having knowledge on your project is that we can provide streamlined workflows that leverage Apple&#39;s building blocks <em>(e.g. <code class="inline">xcodebuild</code>, <code class="inline">simctl</code>)</em>.
Here are some of the features that we are planning,
and that you&#39;ll be able to opt-in easily if you are already using Tuist:</p>
<ul>
  <li>
<strong>Caching:</strong> This is one of the features we are the most excited about building.
Unlike build systems like <a href="https://github.com/facebook/buck">Buck</a> or <a href="https://bazel.build/">Bazel</a>,
which are mostly adopted by large companies that can invest in build systems and tooling,
we are exploring adding caching at the module level.
We&#39;ll generate projects where only the targets you plan to work on will be generated ―
the rest will be pre-compiled frameworks and libraries that we&#39;ll pull from a remote cache.  </li>
  <li>
<strong>Selective builds:</strong> As projects get larger, building everything on CI is inefficient.
For that reason, we&#39;ll combine <a href="https://git-scm.com/">Git</a> information with your project&#39;s dependency graph to determine what needs to be built.
In plain words, we&#39;ll build  </li>
  <li>
<strong>Selective test runs:</strong> Similar to the above, we&#39;ll provide a command to run only the tests that are impacted by your code changes. For that, we plan to use <code class="inline">xcodebuild</code> in combination with the <code class="inline">--only-testing</code> argument.  </li>
  <li>
<strong>Run apps from the terminal:</strong> As great as it sounds,
you&#39;ll have a command,
<code class="inline">tuist run</code>,
to run any app in the selected destination <em>(e.g. iOS simulator)</em>.
A good use case for this feature is trying out an example app from any of the frameworks of the project,
without having to open Xcode.  </li>
  <li>
<strong>Dynamic documentation:</strong> A <code class="inline">tuist doc</code> command, inspired by <a href="https://doc.rust-lang.org/cargo/commands/cargo-doc.html">Cargo&#39;s doc command</a>, will generate dynamic documentation from the code that belongs to the project in the directory where the command is run from. Thanks to it, you will no longer have to depend on another tool, or add more configuration files.  </li>
</ul>
<h2 id="some-final-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Some final words<a href="#some-final-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Some final words"></a></h2>
<p>
At Tuist, we are aiming to help teams be <strong>productive when working with projects of any scale</strong>.</p>
<p>
We are aware that not all the projects can have a tooling or infrastructure team,
and for that reason,
we are designing features optimizing for <strong>zero configuration</strong>.
Instead of having to depend on many tools to do your job <em>(e.g. project generators, <a href="https://docs.fastlane.tools/">Fastlane</a>, <a href="https://github.com/ruby/rake">Rake</a>, documentation generator)</em>,
you&#39;ll depend on just one that will make your projects the source of truth.</p>
<p>
Unlike many developers,
we believe <strong>that a large scale doesn&#39;t mean complexity.</strong>
Therefore,
we are making a huge effort to not port complexity from Xcode over to Tuist.
Furthermore,
we are providing developers guidance on <a href="https://community.tuist.io">our community forum</a> and <a href="https://slack.tuist.io">Slack group</a>,
to get rid of the accidental complexity that they have accumulated over the years.</p>
<p>
If there&#39;s one important thing that I&#39;d like you to take away from this blog post, that is: <code class="inline">large != complex</code>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.7.1 - Edit all manifests, safer build settings API and SwiftUI projects ]]></title>
      
      
      <author>
        <name><![CDATA[ Natan Rolnik ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Easier manifests editing and safer configurations with Tuist 1.7.1 ]]></summary>
      <link href="https://tuist.dev/blog/2020/04/21/version-171"/>
      <id>https://tuist.dev/blog/2020/04/21/version-171</id>
      <updated>Tue, 21 Apr 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist&#39;s latest version, 1.7.1, has features developed by new contributors 👋🏻. Before joining me for an overview and
other significant changes in this version, bear in mind that version 1.7.0 was published
and we detected a critical bug due to a library incorrectly linked to the binary.
After the community identified the bug, <a href="https://www.github.com/pepicrft">Pedro</a> quickly fixed the issue and
released 1.7.1. If you have issues with 1.7.0, you can
<a href="https://github.com/tuist/tuist/issues/1249#issuecomment-617275456">read here</a> how to fix it.</p>
<h2 id="edit-all-manifests-in-one-single-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
Edit All Manifests in One Single Project<a href="#edit-all-manifests-in-one-single-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Edit All Manifests in One Single Project"></a></h2>
<p>
If you worked with many Project.swift files across different projects, chances are high that you got tired of
changing directories and running <code class="inline">tuist edit</code>. Thanks to <a href="https://github.com/julianalonso">Julian</a>&#39;s
first contribution to Tuist, this is over. From now on, <code class="inline">tuist edit</code> will find recursively all <code class="inline">Project.swift</code>
files within your current directory and create an Xcode project with all of them.</p>
<h2 id="syntactic-sugar-api-for-defining-build-settings" tabindex="-1" class="marketing__blog_post__body__content__heading">
Syntactic Sugar API for Defining Build Settings<a href="#syntactic-sugar-api-for-defining-build-settings" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Syntactic Sugar API for Defining Build Settings"></a></h2>
<p>
Another addition in this release is related to defining project and targets settings. Before this version, one would
define settings in the following way:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let baseSettings: [String: SettingValue] = [
  &quot;ENABLE_BITCODE&quot;: &quot;YES&quot;,
  &quot;SWIFT_COMPILATION_MODE&quot;: &quot;wholemodule&quot;,
]    </shiki-highlight>
  </div>
</div>
<p>
This is not ideal. Having to repeat the strings manually and finding the possible values is not only tedious, but also
might lead to errors, since typos in strings are a common problem. Initially, I found myself using a few functions in
my <a href="https://docs.old.tuist.io/guides/helpers/">project description helpers</a> to make the settings both type safety and to reduce duplication
of the strings. I raised the topic in the Tuist Slack group and adding these functions to <code class="inline">ProjectDescription</code> was a
welcome idea. This is exactly within the goals of Tuist: to make developers&#39; life easier and the task of generating
projects less error prone. From now on, the code above can be written like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let baseSettings = SettingsDictionary()
    .bitcodeEnabled(true)
    .swiftCompilationMode(.wholemodule)    </shiki-highlight>
  </div>
</div>
<p>
<a href="https://docs.old.tuist.io/manifests/project/#settingsdictionary">Refer to the documentation</a> to see the list of built in
functions, and also to learn how you can add your own to your project description helpers. If you find yourself using a
function that others can leverage as well, don&#39;t hesitate to open a Pull Request adding them.</p>
<h2 id="behind-the-scenes-and-swiftui" tabindex="-1" class="marketing__blog_post__body__content__heading">
Behind the Scenes and SwiftUI<a href="#behind-the-scenes-and-swiftui" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Behind the Scenes and SwiftUI"></a></h2>
<p>
Thanks to the efforts of <a href="https://github.com/fortmarek">Marek</a> and <a href="https://github.com/mollyIV">Daniel</a>,
Tuist now uses <a href="https://github.com/apple/swift-argument-parser">Apple&#39;s Swift Argument Parser</a> to parse the received
commands instead of SPM&#39;s parser (which will be eventually abandoned in favor of this new one).
The refactor done to adopt the new parser required Tuist to have a better separation of concerns,
so our code is even better now 💪.</p>
<p>
Another contribution by Marek is the support for generating new SwiftUI-based project with the
<a href="https://docs.old.tuist.io/commands/scaffold/">new <code class="inline">scaffold</code> command</a>.</p>
<p>
If you would like to see all the changes in this version, check them out in the
<a href="https://github.com/tuist/tuist/releases/tag/1.7.0">release page</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.5.0 - Scaffold command, performance, Mint ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist's new version 1.5.0 brings scaffold command, performance improvements and Mint support ]]></summary>
      <link href="https://tuist.dev/blog/2020/03/25/version-150"/>
      <id>https://tuist.dev/blog/2020/03/25/version-150</id>
      <updated>Wed, 25 Mar 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist is being worked on even from home 🏡 and I am stoked to present to you what&#39;s new.
It&#39;s not even so long ago that the version 1.4.0 has been released, but there&#39;s already enough new improvements to justify a new one!
That includes a brand new command <code class="inline">scaffold</code>, or <a href="https://github.com/yonaskolb/Mint">Mint</a> suppport, besides new features we are working hard on making generation faster and more performant 🏎
Let&#39;s see in detail what this release brings.</p>
<h2 id="scaffold-command" tabindex="-1" class="marketing__blog_post__body__content__heading">
Scaffold command<a href="#scaffold-command" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Scaffold command"></a></h2>
<p>
A lot of teams or even individuals have some common structure for their features or components,
but creating a new one has meant using a custom solution or copy&amp;paste,
which is tedious and takes away time that developers can focus on coding.</p>
<p>
To fix this common problem we are introducing a new <code class="inline">scaffold</code> command.
For example if you use modular architecture with feature frameworks,
you can set up a new manifest called <code class="inline">Template.swift</code> to generate
<code class="inline">Project.swift</code>, tests and an example.
Then you can run <code class="inline">tuist scaffold framework --name MyFramework</code> and you&#39;re all set!
Or if you want to create a new feature framework following VIPER architecture,
you might call <code class="inline">tuist scaffold viper --name Home</code>. The possibilites are really endless 🙂
To read more about how it works you can do so on <a href="https://docs.old.tuist.io/commands/scaffold/">commands</a> documentation page.</p>
<p>
We are excited too see what <em>you</em> will be able to do with it!</p>
<h2 id="performance-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Performance improvements<a href="#performance-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Performance improvements"></a></h2>
<p>
<a href="https://github.com/kwridan">Kas</a> has been hard at work at making Tuist more performant,
which will make interacting with large projects even more delightful.</p>
<p>
Besides <a href="https://github.com/Tuist/Tuist/pull/1094">optimizing</a> build phase generator,
I&#39;d point out an astonishing 50 % speed improvement of <a href="https://github.com/Tuist/Tuist/pull/1096">WorkspaceGenerator</a>
by implementing concurrent project generation.</p>
<h2 id="mint-support" tabindex="-1" class="marketing__blog_post__body__content__heading">
Mint support<a href="#mint-support" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Mint support"></a></h2>
<p>
If you use <a href="https://github.com/yonaskolb/Mint">Mint</a>,
we have some good news, too.
Thanks to the magnificent <a href="https://github.com/Tuist/Tuist/pull/1131">job</a> by <a href="https://github.com/mollyIV">Daniel</a>,
it is now supported in <code class="inline">Setup.swift</code>.</p>
<p>
To get yourself going, just make sure you have Mintfile in your directory
and add <code class="inline">.Mint()</code> to <code class="inline">Setup.swift</code>.</p>
<p>
It will then download all dependencies
and it makes setting up developer&#39;s workspace even easier.</p>
<h2 id="bug-fixes-and-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug fixes and improvements<a href="#bug-fixes-and-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug fixes and improvements"></a></h2>
<ul>
  <li>
<a href="https://github.com/Tuist/Tuist/pull/1095">TargetNode</a> set operations optimization  </li>
  <li>
<a href="https://github.com/Tuist/Tuist/pull/1128">Graphing</a> protocol removed  </li>
</ul>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.4.0 - Lint command, more verbose logs, and configuration of the project organization ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The just released version of Tuist, 1.4.0, adds support for printing more verbose logs, and configuring the Xcode organization. ]]></summary>
      <link href="https://tuist.dev/blog/2020/03/16/version-140"/>
      <id>https://tuist.dev/blog/2020/03/16/version-140</id>
      <updated>Mon, 16 Mar 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
In difficult times where 🦠 COVID-19 presented the world with an unprecedented challenge,
Tuist maintainers and contributors continue devoting their time to help companies scale up their Xcode projects.
All the effort that they put into the project is reflected in a new release that we are announcing in this blog post, 1.4.0.
Although there aren&#39;t major features shipping this time, there are small features and improvements that you might find handy for your projects.
Let&#39;s dive right into what those improvements are.</p>
<h2 id="configure-the-organization-name" tabindex="-1" class="marketing__blog_post__body__content__heading">
Configure the organization name<a href="#configure-the-organization-name" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Configure the organization name"></a></h2>
<p>
As you probably know,
when you create a new project in Xcode,
one of the fields that you need to fill out is the name of the organization.
That information ends up codified in your projects
and Xcode uses it to create copyright headers when adding new files.</p>
<p>
Until today,
configuring that in Tuist was not possible,
but thanks to <a href="https://github.com/c0diq">Sylvain</a>&#39;s <a href="https://github.com/tuist/tuist/pull/1062">amazing contribution</a>,
that&#39;s finally possible.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// It can be configured at the project level
let project = Project(organizationName: &quot;Tuist&quot;)

// Or globaly in the config file
let config = Config(organizationName: &quot;Tuist&quot;)    </shiki-highlight>
  </div>
</div>
<h2 id="verbose-argument" tabindex="-1" class="marketing__blog_post__body__content__heading">
Verbose argument<a href="#verbose-argument" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Verbose argument"></a></h2>
<p>
Despite our efforts to handle all possible scenarios in Xcode projects gracefully,
we may miss some.
The consequence of that is that developers get unexpected results that we need to debug and fix.
To make that work easier,
we <a href="https://github.com/tuist/tuist/pull/1027">introduced support for a new argument</a>, <code class="inline">--verbose</code>,
that configures the output to be more verbose.
When passed to any of the commands,
the output contains information that is useful to understand the issue and provide users with a solution as soon as possible.</p>
<h2 id="lint-command" tabindex="-1" class="marketing__blog_post__body__content__heading">
Lint command<a href="#lint-command" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Lint command"></a></h2>
<p>
As part of the project generation,
we lint your project definition to uncover errors that otherwise would cause compilation issues later on.
If developers wanted to run the linting logic without generating the project,
there was no option to do so.
Fortunately, that changes with Tuist 1.4.0 because it introduces <a href="https://github.com/tuist/tuist/pull/1043">a new command</a> <code class="inline">tuist lint</code>.
You can read more about how it works on the <a href="https://docs.old.tuist.io/commands/linting/">commands</a> documentation page.</p>
<p>
If you are currently using Tuist,
we recommend you to set up a CI pipeline that runs that command for every commit.
That&#39;ll fail PRs immediately before <code class="inline">xcodebuild</code> starts compiling the project.
The developers will get faster feedback and therefore waste less time waiting for the build system to surface issues in the shape of compilation errors.</p>
<h2 id="tuistconfig.swift-renamed-to-config.swift" tabindex="-1" class="marketing__blog_post__body__content__heading">
TuistConfig.swift renamed to Config.swift<a href="#tuistconfig.swift-renamed-to-config.swift" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to TuistConfig.swift renamed to Config.swift"></a></h2>
<p>
Since <code class="inline">TuistConfig.swift</code> is a file that contains configuration that is global to all the projects in the same directory and subdirectories,
we decided that it makes more sense to require it to be in a directory where other global files are <em>(e.g. project description helpers)</em>.
That directory is the root <code class="inline">/Tuist</code> directory.</p>
<p>
For that reason, from Tuist 1.4.0 the file <a href="https://github.com/tuist/tuist/pull/1083">is expected to be</a> under <code class="inline">/Tuist</code> and with the name <code class="inline">Config.swift</code> to avoid some naming redundancy.
Since this is a minor release,
and we follow <a href="https://semver.org/">semantic versioning</a>,
we made this change a non-breaking change.
In other words,
it does not break your current projects if you follow the old convention.
However,
we encourage you to move the file to the new directory and change its name.
That&#39;ll make the future adoption of major releases a seamless process.</p>
<h2 id="website-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Website improvements<a href="#website-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Website improvements"></a></h2>
<p>
As you might have noticed,
the website looks a bit different than the last time you visited it.
That&#39;s because we gave it a facelift to have consistent and themeable styling.
That makes the website more accessible and more pleasant to navigate.
There&#39;s a tiny button at the top-right corner that you can use to adjust the theme to the one you find the most comfortable to your taste.
For those of you who are curious about how we achieved that so quickly while other website takes a lot of time to introduce theming,
we used the package <a href="https://theme-ui.com/">theme-ui</a>,
that provides a beautiful and concise abstraction for consistently styling <a href="https://reactjs.org/">React</a> website.
If you are considering implementing a statically-generated website,
we strongly recommend the combo <a href="https://www.gatsbyjs.org/">GatsbyJS</a> with theme-ui.
Once you know the basic building blocks,
creating a website becomes very straightforward.</p>
<h2 id="bug-fixes-and-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug fixes and improvements<a href="#bug-fixes-and-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug fixes and improvements"></a></h2>
<ul>
  <li>
<a href="https://github.com/tuist/tuist/pull/1037">Support</a> spaces in <code class="inline">TargetAction</code> for <code class="inline">PROJECT_DIR</code>.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/1081">Fix</a> compilation issues in the code example that is shown in the &quot;Project description helpers&quot; documentation.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/1007">Introduce descriptors</a> to remove side effects and IO during project generation to ease optimizations and make the process more deterministic.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/1084">Add a new TuistInsights</a> target to start working on a cloud-based feature to help teams make informed decisions on PRs based on collected insights.  </li>
</ul>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.3.0 - Performance improvements and generation of projects while editing ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The newest release brings you many bugfixes and improvements. However with the number of contributors steadily growing the team has also been busy thinking and writing about the direction of Tuist. We have a rough plan for Tuist 2.0 and work has started on compiling a manifesto to explain a bit more about the goals and values of the project. ]]></summary>
      <link href="https://tuist.dev/blog/2020/02/26/version-130"/>
      <id>https://tuist.dev/blog/2020/02/26/version-130</id>
      <updated>Wed, 26 Feb 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist 1.3.0 has just <a href="https://github.com/tuist/tuist/releases/tag/1.3.0">been published</a>.
In this blog post,
I&#39;ll walk you through the improvements and fixes that we shipped in this release,
and hint what are the upcoming features that we plan to work on.</p>
<h2 id="generate-the-projects-when-editing-the-project-in-xcode" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generate the projects when editing the project in Xcode<a href="#generate-the-projects-when-editing-the-project-in-xcode" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generate the projects when editing the project in Xcode"></a></h2>
<p>
Tuist has a command,
<code class="inline">tuist edit</code>,
which creates an Xcode project to edit your project manifest files.
The benefit of that is that developers can get inline documentation and validate the syntax by just building the manifest in Xcode.
We know this feature is quite handy,
so <a href="https://github.com/tuist/tuist/pull/958">we improved</a> it by adding support for running <code class="inline">tuist generate</code> directly from Xcode.
The editable Xcode project will have an extra scheme that runs the generation command.
That way users don&#39;t have to go back to the terminal and run <code class="inline">tuist generate</code> manually.</p>
<h2 id="preserve-user-data-when-generating-the-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Preserve user data when generating the projects<a href="#preserve-user-data-when-generating-the-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Preserve user data when generating the projects"></a></h2>
<p>
Xcode projects have files of type <code class="inline">.xcuserdata</code> that Xcode generates with user-specific configuration.
Those files are deleted when projects are generated with <code class="inline">tuist generate</code>.
Thanks to <a href="https://github.com/tuist/tuist/pull/1006">this work</a> that&#39;s not the case anymore.
From Tuist 1.3.0,
<code class="inline">tuist generate</code> generates the projects preserving that data.</p>
<h2 id="performance-related-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Performance-related improvements<a href="#performance-related-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Performance-related improvements"></a></h2>
<p>
The generation of Xcode project <strong>needs to be fast.</strong>
Unfortunately, the performance of the generation logic is something that we have disregarded since the inception of the project, and now some users are hitting slow project generations.
We decided it&#39;s time to tackle this so the first step that we took was adding a <a href="https://github.com/tuist/tuist/pull/957">helper utility</a> that helps us benchmark the performance.
Thanks to it,
we&#39;ll be able to uncover performance bottlenecks and fail pull requests if we introduce regressions.</p>
<p>
Moreover, we made <a href="https://github.com/tuist/tuist/pull/980">some improvements</a> in the logic that sorts the project groups and files getting an improvement of roughly 50%.</p>
<h2 id="project-manifesto" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project manifesto<a href="#project-manifesto" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project manifesto"></a></h2>
<p>
As the project grows,
it&#39;s crucial for users, contributors, and maintainers to know what are our design pillars.
For that reason,
we updated our documentation to include a <a href="https://docs.old.tuist.io/contributors/manifesto/">manifesto</a> that contains a set of principles that are foundational to the design and development of Tuist.
They help align users and contributors with the vision of the project.</p>
<h2 id="installation-from-google-cloud-storage" tabindex="-1" class="marketing__blog_post__body__content__heading">
Installation from Google Cloud Storage<a href="#installation-from-google-cloud-storage" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Installation from Google Cloud Storage"></a></h2>
<p>
Tuist used to install new versions of Tuist by pulling the binaries from the GitHub releases.
As users reported, that caused some issues because GitHub&#39;s API returned limit errors.
To mitigate this issue,
we moved our artifacts to Google Cloud Storage.
Moreover,
we took the opportunity to add support for pulling binaries for incremental builds.
For instance,
if a developer wants to try out a specific commit,
they can run <code class="inline">tuist local commit_sha</code> and Tuist will pull the binaries and make sure that we are running the right version.</p>
<h2 id="other-fixes-and-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other fixes and improvements<a href="#other-fixes-and-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other fixes and improvements"></a></h2>
<p>
Tuist 1.3.0 also ships with minor fixes and improvements that are worth mentioning:</p>
<ul>
  <li>
Added metal as a valid source extension - <a href="https://github.com/tuist/tuist/pull/1023">Link</a>  </li>
  <li>
Fixed false positive warnings during the linting process - <a href="https://github.com/tuist/tuist/pull/981">Link</a>  </li>
  <li>
Added support for target action paths without the <code class="inline">./</code> prefix - <a href="https://github.com/tuist/tuist/pull/997">Link</a>  </li>
  <li>
Ensured bcsymbolmap paths are consistently sorted  </li>
  <li>
Updated XcodeProj to 7.8.0  </li>
  <li>
Added &quot;Base&quot; to the list of known regions - <a href="https://github.com/tuist/tuist/pull/1021">Link</a>  </li>
</ul>
<h2 id="what’s-next" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next<a href="#what’s-next" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next"></a></h2>
<p>
Our goal is to provide teams with a full-fledged tool that helps them deal with their projects at scale. The list of challenges that teams face when scaling up their projects is long:</p>
<ul>
  <li>
Keep consistency across projects.  </li>
  <li>
Ensure that projects are simple and that can be modularized easily.  </li>
  <li>
Seamless management of certificates and profiles.  </li>
  <li>
Have insights about build times and the quality of the project.  </li>
  <li>
Slow build times.  </li>
</ul>
<p>
We are starting to take the steps towards helping teams with those challenges. In fact, we are implementing a simple and standard interface to build and test projects. With it, projects no longer need another layer <em>(e.g. Fastfiles)</em> that can become complex and hard to reason about. If you are in a directory where there’s a Project.swift or a Workspace.swift, you’ll be able to run <code class="inline">tuist build</code> and <code class="inline">tuist test</code>.</p>
<p>
Moreover, we are implementing caching by leveraging <a href="https://developer.apple.com/videos/play/wwdc2019/416/">xcframeworks</a> and project generation. Teams might need to simplify their projects and remove side effects, for example, introduced by script build phases, but the benefits are huge. The only source code that developers will need to compile is the code of the module that they are working on. Transitive and non-transitive dependencies will be xcframeworks.</p>
<blockquote>
  <p>
In other words, we are making scaling Xcode projects easy and fun for the rest of us  </p>
</blockquote>
<p>
It’s an ambitious plan but we are confident we can get there. We can’t move as fast as we’d like to but this slow yet steady pace is helping us keep an eye on the architecture and ensuring it evolves sustainably with the project. If you’d like to be part of the journey and contribute to making it happen join our <a href="https://slack.tuist.io">Slack</a> and let us know. We’ll gladly onboard you and give you pointers to start contributing.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 1.2.0 - Bugfixes, improvements and future direction ]]></title>
      
      
      <author>
        <name><![CDATA[ Vytis ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The newest release brings you many bugfixes and improvements. However with the number of contributors steadily growing the team has also been busy thinking and writing about the direction of Tuist. We have a rough plan for Tuist 2.0 and work has started on compiling a manifesto to explain a bit more about the goals and values of the project. ]]></summary>
      <link href="https://tuist.dev/blog/2020/01/31/version-120"/>
      <id>https://tuist.dev/blog/2020/01/31/version-120</id>
      <updated>Fri, 31 Jan 2020 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
We are slowly learning how to do smaller bi-weekly releases. This release was planned for last week but it was postponed because there were not enough changes. However lots of new things got merged recently and Tuist 1.2.0 is here for you to enjoy!</p>
<h2 id="new-contributors" tabindex="-1" class="marketing__blog_post__body__content__heading">
New contributors<a href="#new-contributors" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to New contributors"></a></h2>
<p>
Firstly, warm welcome to another first-time Tuist contributor <a href="https://github.com/paciej00">Maciej Piotrowski</a> 👏👏👏. He improved the API introduced in the previous release for excluding files from a target. It makes exclude patterns more flexible which can be very useful when migrating an existing project to Tuist!</p>
<h2 id="future-of-tuist" tabindex="-1" class="marketing__blog_post__body__content__heading">
Future of Tuist<a href="#future-of-tuist" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Future of Tuist"></a></h2>
<p>
There are plenty of ideas floating around what other features Tuist should have and <a href="https://github.com/pepicrft">Pedro</a> laid them out in nicely in <a href="https://github.com/tuist/tuist/issues/951">The journey towards Tuist 2.0</a>. In addition, he also opened a work-in-progress PR for Tuist&#39;s <a href="https://github.com/tuist/tuist/pull/952">manifesto</a>. With more and more people joining the project it&#39;s very important to lay down the core principles in writing to ensure that everyone is up to speed. For more practical information we also have a new <a href="https://docs.old.tuist.io/building-at-scale/best-practices/">Best Practices</a> section on the website. It is quite short at the moment, but will contain a growing list of things that can be useful for both new Tuist users and developers trying to improve their setup.</p>
<h2 id="focus-on-improving-performance" tabindex="-1" class="marketing__blog_post__body__content__heading">
Focus on improving performance<a href="#focus-on-improving-performance" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Focus on improving performance"></a></h2>
<p>
A common complaint, especially for bigger projects, is the time it takes to generate the project. The main focus until this point was adding features, but time has come to start thinking about performance. End of last year <a href="https://github.com/kwridan">Kas</a> proposed an <a href="https://github.com/tuist/tuist/issues/820">idea</a> to start performance testing. First part of this initiative already got <a href="https://github.com/tuist/tuist/pull/890">merged</a>. The <a href="https://github.com/tuist/tuist/tree/main/projects/fixturegen">Fixture Generator</a> tool will allow us to easily generate a project with potentially hundreds of targets and iron out performance issues much more systematically. It is just the beginning and the plan is eventually to integrate performance testing as part of GitHub checks so we can be sure that adding new features would not have an impact on project generation times.</p>
<h2 id="full-changelog" tabindex="-1" class="marketing__blog_post__body__content__heading">
Full Changelog<a href="#full-changelog" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Full Changelog"></a></h2>
<p>
Of all the things mentioned, there are also plenty of bugfixes and improvements in this release. The full changelog can be found on the <a href="https://github.com/tuist/tuist/releases/tag/1.2.0">release page</a>.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ API for excluding files with Tuist 1.1.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The new version of Tuist ships with improvements in the API for defining files so that users can exclude files using glob patterns. Moreover, we made some changes in the architecture of the project and introduced two new targets to the family, TuistGalaxy and TuistAutomation. ]]></summary>
      <link href="https://tuist.dev/blog/2019/12/27/version-110"/>
      <id>https://tuist.dev/blog/2019/12/27/version-110</id>
      <updated>Fri, 27 Dec 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist 1.1.0 has been released and is shorter than usual because we have committed to a fixed biweekly.
In the past,
users were in situations where their projects were pointing to commits in main.
Although that&#39;s possible thanks to <a href="https://docs.old.tuist.io/guides/version-management/">Tuist&#39;s version management</a>, that&#39;s an undesirable state to be in.
We chose two weeks as the cadence because a week is to short as to be able to ship noticeable changes,
and more than two weeks likely leaves users waiting for improvements and bug fixes coming along with new versions.</p>
<p>
Besides committing to a fixed release schedule,
this version also ships with support for <a href="https://github.com/tuist/tuist/pull/811"><strong>excluding files</strong></a> thanks to <a href="https://github.com/vytis">Vytis&#39;s</a> first code-contribution to the project.
Some users reported that the current API was a bit limiting and that they could not express their project files <em>concisely</em>.
Although we firmly believe that we should aim to keep the files structure simple,
we also understand that users might come from complex setups that they might want to express in their manifests.</p>
<p>
You can adopt the new API easily. In those places where you define glob patterns to match files,
you can use the constructor of the underlying type and pass the <code class="inline">excluding</code> argument:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let target = Target(sources: [.init(&quot;Sources/**/*.swift&quot;, excluding: &quot;**/Excluded.swift&quot;)])    </shiki-highlight>
  </div>
</div>
<p>
In case one was not enough,
Vytis made another great contribution to the project.
He improved the <a href="https://github.com/tuist/tuist/pull/811">generation of schemes</a> so that the autogenerated schemes from targets that have dependant testables, have test actions too.
In other words, the scheme <code class="inline">MyFramework</code> that is generated for the framework <code class="inline">MyFramework</code>,
which has an associated <code class="inline">MyFrameworkTests</code>,
has a test action defined to run tests.</p>
<h3 id="internal-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Internal improvements<a href="#internal-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Internal improvements"></a></h3>
<p>
To ensure a healthy and sustainable growth of the project,
in this version,
we are also shipping some internal improvements.
We created <a href="https://github.com/tuist/tuist/pull/817">two new frameworks</a>.
The first one will contain all the logic for caching output artifacts to speed up builds, something that we have already started working on.
The latter will contain the logic for commands such as <code class="inline">tuist build</code>, or <code class="inline">tuist test</code> that will define an standard CLI to interact with the projects.</p>
<h3 id="how-to-update" tabindex="-1" class="marketing__blog_post__body__content__heading">
How to update<a href="#how-to-update" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How to update"></a></h3>
<p>
As always, updating Tuist is as simple as running the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist update    </shiki-highlight>
  </div>
</div>
<h3 id="happy-holidays" tabindex="-1" class="marketing__blog_post__body__content__heading">
Happy holidays<a href="#happy-holidays" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Happy holidays"></a></h3>
<p>
We hope you are having a wonderful time with family and friends and using this time to recharge the batteries and plan 2020.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist turns 1.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Today we are pleased the first major release of Tuist, 1.0. We have achieved an important milestone in helping teams scale up their projects, making defining projects easy, and for that reason we are releasing this one as major. This blog post describes what that has been for the project, and what are our ambitions for Tuist 2.0. ]]></summary>
      <link href="https://tuist.dev/blog/2019/12/18/version-100"/>
      <id>https://tuist.dev/blog/2019/12/18/version-100</id>
      <updated>Wed, 18 Dec 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Today is an essential day in the history of Tuist; we just cut the first major release of the project, 1.0.0.
I started it with the motivation of <strong>making defining Xcode projects an easy task</strong> regardless of their size,
so easy that anyone in the team could participate in scaling up projects.
I was a bit irritated by having to translate dependencies into build settings and build phases with the risk of breaking things if I did something wrong. Not to talk about the number of <strong>git conflicts</strong> that we often saw in developers’ PRs.
That had a significant impact on developers&#39; productivity because PRs took longer to merge.</p>
<p>
I remember talking in conferences about a frameworks&#39; architecture that we came up with at <a href="https://soundcloud.com">SoundCloud</a> and that I ended up calling <strong>uFeatures</strong>.
In hindsight,
it was a great idea but were starting to suffer from the maintenance burden.
None of the tools out there allowed me to define my projects easily,
in plain language,
and with the option to describe the structure in such a way that is reusable.
<a href="https://cocoapods.org">CocoaPods</a> was the closest option but is opinionated about the structure of the Pods and how they integrate into the projects.
<em>Why not building something to solve this problem that I have?</em> I wanted to write it in Swift,
but unlike in Ruby,
there was no <a href="https://github.com/cocoapods/xcodeproj">XcodeProj</a> library to generate Xcode projects following Xcode’s convention.
For that reason, I had to spend some time developing XcodeProj,
a library to read,
update,
and write Xcode projects.
Nowadays, it’s being used by many projects, and we keep updating it to support features introduces by new Xcode versions.</p>
<p>
<strong>Tuist has matured a lot</strong> since I coded the first line right after finishing with XcodeProj. Conversely to what many people think,
Tuist <strong>is more than just a project generation tool</strong>;
it&#39;s a tool that enables teams to scale up their projects,
To do so,
We designed it based upon a simple,
yet powerful idea: <em>keep it simple</em>.
We conceptually compressed ideas from Xcode to make the projects easier to reason about. We default to conventions yet allow developers to define theirs. Furthermore, we understand that one of the maintenance difficulties comes from barely being able to reuse bits across projects, so we made it super easy.</p>
<p>
We have achieved the first milestone for the project,
<strong>simplifying the definition of projects of any size</strong>,
and for that reason we decided to cut this as a major release.
In this blog post,
I’d like to dive into some important features that we bundled in this release,
and I’ll spoil what will be our focus for version 2.0.</p>
<blockquote>
  <p>
If you already have Tuist installed, run <code class="inline">tuist update</code> to get the latest version. Otherwise you can execute <code class="inline">bash &lt;(curl -Ls https://install.tuist.io)</code> to install it.  </p>
</blockquote>
<h2 id="what’s-new-in-1.0.0" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s new in 1.0.0<a href="#what’s-new-in-1.0.0" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s new in 1.0.0"></a></h2>
<h3 id="project-description-helpers" tabindex="-1" class="marketing__blog_post__body__content__heading">
Project description helpers<a href="#project-description-helpers" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Project description helpers"></a></h3>
<p>
While Tuist supported defining workspaces that are,
in essence,
projects organized in multiple Xcode projects,
it was not possible to extract content from the manifest files <em>(e.g Project.swift)</em> to be reused by other files.
In <strong>modular projects</strong>, this becomes very handy because most of the projects follow a similar structure with minor differences.
Unfortunately, neither Xcode nor existing Swift tooling allows that.</p>
<p>
Let me tell you that Tuist 1.0.0 makes that super easy using <strong>project description helpers</strong>.
They are a group of Swift files that get compiled under a <code class="inline">ProjectDescriptionHelpers</code> module that can be imported by your manifest files.
Tuist is not opinionated about the content and the structure of those files,
so it’s really up to you to define how you want to use them.</p>
<p>
Helpers are a powerful tool to <strong>codify conventions.</strong>
You can define a function that acts as a factory of projects;
it can take the name a list of dependencies and returns a project.
They are also handy to <strong>simplify the definition of projects</strong>.
You can take the definition of projects down to a line of code.
<em>Can you imagine the number of git conflicts that you are cutting?</em></p>
<blockquote>
  <p>
Change it in one place, get it everywhere.  </p>
</blockquote>
<p>
The example below shows how we can use helpers to define the structure of a feature framework project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.featureFramework(
  name: &quot;Home&quot;,
  dependencies: [
    .project(target: &quot;Features&quot;, path: &quot;../Features&quot;),
    .framework(path: &quot;Carthage/Build/iOS/SnapKit.framework&quot;)
    .package(product: &quot;KeychainSwift&quot;)
  ]
)    </shiki-highlight>
  </div>
</div>
<h3 id="editing-manifests" tabindex="-1" class="marketing__blog_post__body__content__heading">
Editing manifests<a href="#editing-manifests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Editing manifests"></a></h3>
<p>
As you might know, in Tuist, <strong>manifests are defined in Swift.</strong>
Using Swift has proven to be a great idea because it allows editing the file in Xcode and leveraging features such as <strong>code autocompletion and inline documentation.</strong>
<em>Handy, isn’t it?</em>
Before this version,
we generated targets to edit the manifest files as part of the generated projects.
While that worked,
we believe it&#39;s not the right approach because the generated projects would have a dependency on Tuist.
That’s something we&#39;d like to avoid,
and for that reason,
we introduced a new command: <code class="inline">tuist edit</code>.</p>
<p>
Tuist edit creates a temporary Xcode project to edit the manifests in the current directory and its dependencies <em>(e.g Project description helpers)</em>.
Once users are done with editing, the project is destroyed automatically.
The generated project supports the project description helpers mentioned above.
Those are placed in another target that can be imported from the manifest files.</p>
<h3 id="new-website" tabindex="-1" class="marketing__blog_post__body__content__heading">
New website<a href="#new-website" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to New website"></a></h3>
<p>
<em>Did you notice the fresh design we shipped with this major version?</em>
Our previous design did not accurately <strong>convey the values of Tuist</strong>,
and did an abysmal job at explaining developers why a tool like Tuist is crucial for a sustainable scale of projects.
Moreover,
the documentation was generated using a different tool and with a different design that made it feel detached and inconsistent with the website.
Now documentation is generated as part of the website and follows the same style guidelines.</p>
<p>
We have made sure that all pages contain semantically-correct HTML, and structured data and meta elements to help search engines like Google index the content and make it easily browsable.</p>
<p>
For those of you interested in knowing how we made it happen, we got a lot of inspiration from <a href="https://dribbble.com/">Dribbble</a>, and did the whole design using <a href="https://dribbble.com/">Figma</a>. The website is part of the Tuist’s monorepo under <code class="inline">/website</code> and statically generated using Gatsby in combination with powerful libraries like Gatsby.</p>
<p>
We believe that poor user experiences diminish the value of the software,
and for that reason,
<strong>we pay attention to every detail of crafting Tuist</strong>.</p>
<h2 id="the-journey-towards-2.0" tabindex="-1" class="marketing__blog_post__body__content__heading">
The journey towards 2.0<a href="#the-journey-towards-2.0" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to The journey towards 2.0"></a></h2>
<p>
So having achieved this important milestone, one might wonder <strong>what’s next?</strong></p>
<p>
Project generation is not done yet. We don’t fully support all types of products, so we’d like to add support for some of them <em>(e.g intent extensions)</em>. We could map Xcode concepts 1-to-1 and have support very quickly,
but we follow a different approach.
We thoroughly study Xcode concepts with the aim of finding simplification opportunities.
We believe the key to scale is simpler concepts, not concepts in other languages.</p>
<p>
The project has a substantial and well-architected foundation with an easy-to-extend generation logic.
We’ll continue iterating on it because we believe it can pave the way for other tools to come up with <strong>new workflows for developers</strong>.
Like we did with <a href="https://github.com/tuist/xcodeproj">XcodeProj</a>,
we are not only giving tools to the community but libraries that they can reuse as they wish.</p>
<p>
The focus for Tuist 2.0 we’ll be placed in two areas: <strong>automation and productivity.</strong></p>
<h3 id="productivity" tabindex="-1" class="marketing__blog_post__body__content__heading">
Productivity<a href="#productivity" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Productivity"></a></h3>
<p>
The most significant challenge companies face when scaling up projects is <strong>build times.</strong>
Incremental builds are not enough,
and Apple is not doing things better but worse with every Xcode &amp; macOS update.
Only large companies like <a href="https://pinterest.com">Pinterest</a>,
<a href="https://lyft.com">Lyft</a>,
<a href="https://uber.com">Uber</a>,
or <a href="https://airbnb.com">Airbnb</a> can invest in replacing Xcode’s build system with alternatives like <a href="https://buck.build/">Buck</a> or <a href="https://bazel.build/">Bazel</a>.
Even with that,
they have to reverse-engineer Xcode’s functionality,
and put a lot of effort into making builds fast without taking developers away from Xcode.</p>
<p>
Not everyone is a large company, so I’d like <strong>Tuist to be the tool that speeds up the builds for the rest of us.</strong>
I might be going down a rabbit hole,
but based on some tests I’ve done,
I think it’s feasible.
The idea is leveraging the generation logic to replace dependencies with their precompiled version that is pulled from a remote cache.
Tuist has already all the elements in place to make this possible,
so we just need to implement it,
and make sure it’s incredibly efficient.</p>
<p>
Speaking about <strong>efficiency</strong>,
we’ll revisit the generation of projects to make sure it works as fast as possible.</p>
<h3 id="automation" tabindex="-1" class="marketing__blog_post__body__content__heading">
Automation<a href="#automation" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Automation"></a></h3>
<p>
When we talk about automation in mobile,
the first thing that pops up in developer minds is <a href="https://fastlane.tools/">Fastlane</a>.
These days,
defining a CLI for your mobile projects without Fastlane is inconceivable.</p>
<p>
Fastlane is great;
it saved a lot of time to companies and gave a lot of useful libraries to the community.
However, when used at scale,
it often results in complex and unmaintainable <code class="inline">Fastfiles</code>.
It’s not Fastlane’s fault.
It just happens,
and it’s hard to prevent unless you are more opinionated and provide simple conventions that developers stick to.</p>
<p>
I still remember when I landed on a project, and I had to spend some time figuring out the name of the task that I wanted to execute.
Is it <code class="inline">build_app_debug</code>? <code class="inline">debug_app_build</code>? Or perhaps <code class="inline">app_debug_build</code>?</p>
<p>
Imagine you didn’t have to add a <code class="inline">Fastfile</code>.
Imagine you had a simple CLI that you could memorize and use in any directory with a <code class="inline">Project.swift</code> file.
That’s what the <a href="https://swift.org/package-manager/">Swift Package manager</a> and <a href="https://crates.io/">Cargo</a>,
Rust’s dependency manager, do.
Do you want to build the app,
just pass the <code class="inline">build</code> argument.
<em>What if you want to test it?</em>
In that case,
you need to pass the <code class="inline">test</code> argument.</p>
<p>
Having a <strong>conventional</strong> interface in the CLI removes an unnecessary point of friction when developers interact with the projects.
They don’t have to remember all possible combination of arguments that need to be passed to compile an app.
If you take iOS,
for instance,
you probably know that getting <code class="inline">xcodebuild build</code> to succeed is a hard task because you have to remember all the arguments that are required, like the <code class="inline">destination</code>, or the right build settings to disable the signing.</p>
<p>
I want Tuist to port the Swift Package Manager and Cargo’s approach to any Xcode project defined with Tuist.
The commands should work <strong>without any extra arguments</strong> but have the option to pass those when necessary.</p>
<p>
We’ll start with the most common ones, build and test,
and then move to some not-so-common yet useful for developers,
<code class="inline">run</code>,
and <code class="inline">docs</code>.
The latter would generate and open in the browser documentation for the project in the current directory.</p>
<h2 id="one-more-thing" tabindex="-1" class="marketing__blog_post__body__content__heading">
One more thing<a href="#one-more-thing" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to One more thing"></a></h2>
<p>
Automation and productivity will be our focus,
but there are some other ideas in the <strong>backlog</strong> that might end up landing on Tuist 2.0 too:
management of certificates and provisioning profiles, support for static libraries with resources, selective builds based on the file changes, publishing of apps, linting of code.
It&#39;s been years of weakly integrated tooling that is turning brittle as projects get more complicated.
Therefore,
we&#39;d like Tuist to be a <strong>platform</strong> to streamline the processes for building, testing, and releasing Xcode apps into a simple, conventional, and unified solution.</p>
<h2 id="some-final-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Some final words<a href="#some-final-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Some final words"></a></h2>
<p>
Tuist is <strong>the most exciting project I’ve worked on in the open</strong>.
We explore ways of scaling Xcode projects without constraining our ideas and solutions to what the developers are used to or have seen in other tools. We craft what we believe brings joy to working with Xcode.
I know this sounds very Marie Kondo,
but programming should not be complex,
and that&#39;s where we are seeing Xcode going towards.</p>
<p>
I&#39;d like to take the opportunity to thank <strong>maintainers and contributors</strong> that trust the project,
and without whom,
Tuist would not have been possible.
Thanks,
<a href="https://github.com/kwridan">Kas</a>, <a href="https://github.com/marciniwanicki">Marcin</a>, <a href="https://github.com/ollieatkinson">Ollie</a>, <a href="https://github.com/fortmarek">Marek</a>, <a href="https://github.com/adamkhazi">Adam</a>, <a href="https://github.com/lakpa">Lakpa</a>,
and the <a href="https://github.com/orgs/tuist/people">large list of contributors</a> of the organization.
We should not disregard that Tuist&#39;s is the result of a shared effort of very talented people like them that devote part of their time to help others.</p>
<p>
I hope you have a wonderful Christmas with the family and friends ❄️.
Remember that Christmas is time for disconnecting,
put our laptops aside,
and recharging our batteries that have gone through an intense ride this year.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Define your watchOS apps and extensions easily with Tuist 0.19.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Until today, defining watchOS apps and extensions in Tuist was not possible. The good news is that from Tuist 0.19.0 that's no longer true because it extends its beautifully simplified abstractions to watchOS. On top of that, we also shipped support for enabling test coverage in the schemes, and defining the deployment targets in targets. We also took the opportunity to iron out some bugs that had been reported by users. ]]></summary>
      <link href="https://tuist.dev/blog/2019/11/19/version-0190"/>
      <id>https://tuist.dev/blog/2019/11/19/version-0190</id>
      <updated>Tue, 19 Nov 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hola Xcoders 👋!</p>
<p>
Last week we cut a new version of Tuist, 0.19.0, and this time it&#39;s my turn to share what we bundled in that release for you. Let&#39;s dive right in.</p>
<h2 id="support-for-watchos-apps" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support for watchOS apps<a href="#support-for-watchos-apps" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support for watchOS apps"></a></h2>
<p>
Since this version of Tuist you can <a href="https://github.com/tuist/tuist/pull/623/files">now define your apps for watchOS</a>. As we&#39;ve done with other Xcode&#39;s intricacines, Tuist takes care of setting up the build phases and build settings for you. The snippet below contains an example of a project that has a watch app and its companion extension.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let project = Project(name: &quot;App&quot;,
                      targets: [
                        Target(name: &quot;WatchApp&quot;,
                               platform: .watchOS,
                               product: .watch2App,
                               bundleId: &quot;io.tuist.App.watchkitapp&quot;,
                               infoPlist: &quot;Support/WatchApp-Info.plist&quot;,
                               resources: &quot;WatchApp/**&quot;,
                               dependencies: [
                                    .target(name: &quot;WatchAppExtension&quot;)
                               ]),
                      Target(name: &quot;WatchAppExtension&quot;,
                               platform: .watchOS,
                               product: .watch2Extension,
                               bundleId: &quot;io.tuist.App.watchkitapp.watchkitextension&quot;,
                               infoPlist: &quot;Support/WatchAppExtension-Info.plist&quot;,
                               sources: [&quot;WatchAppExtension/**&quot;],
                               resources: [&quot;WatchAppExtension/**/*.xcassets&quot;],
                               dependencies: [])
                      ])    </shiki-highlight>
  </div>
</div>
<p>
Although there are some improvements <a href="https://github.com/tuist/tuist/issues/628">pending to be implemented</a>, the feature is ready for users to start using it in their projects.</p>
<h2 id="support-for-sticker-extension-&-app" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support for sticker extension &amp; app<a href="#support-for-sticker-extension-&-app" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support for sticker extension & app"></a></h2>
<p>
In the vein of adding support for more product types, this version of Tuist also includes <a href="https://github.com/tuist/tuist/pull/489">support for sticker extensions and apps</a>. You can find <a href="https://github.com/Rag0n/tuist/blob/201d39e5e37b7cbd634d702e91e76791919efe95/fixtures/ios_app_with_extensions/Project.swift">an example here</a> of an app with a stickers extension and app.</p>
<h2 id="support-for-enabling-test-coverage-in-schemes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support for enabling test coverage in schemes<a href="#support-for-enabling-test-coverage-in-schemes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support for enabling test coverage in schemes"></a></h2>
<p>
Before this version of Tuist, it was not possible to enable test coverage in schemes. Thanks to <a href="https://github.com/abbasmousavi">Abbas</a>&#39;s work, it&#39;s now possible and there&#39;s an API for that. If you would like to enable it in your custom schemes, you just need to pass the <code class="inline">codeCoverageTargets</code> attribute when initializing a <code class="inline">TestAction</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let test = TestAction.targets([&quot;MyAppTests&quot;], codeCoverageTargets: true)    </shiki-highlight>
  </div>
</div>
<p>
You can check the documentation of the <code class="inline">TestAction</code> model <a href="https://docs.old.tuist.io/usage-projectswift#test-action">here</a>.</p>
<h2 id="defining-the-deployment-target" tabindex="-1" class="marketing__blog_post__body__content__heading">
Defining the deployment target<a href="#defining-the-deployment-target" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Defining the deployment target"></a></h2>
<p>
Thanks to <a href="https://github.com/mollyIV">Daniel</a>&#39;s contribution, developers will be able to specify the deployment target right in the definition of the target. Tuist will generate the right build settings for the targeted device and minimum runtime version. The snippet below includes an example of an app&#39;s target definition that uses the new <code class="inline">deploymentTarget</code> attribute:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let target = Target(name: &quot;App&quot;,
                    platform: .iOS,
                    product: .app,
                    bundleId: &quot;io.tuist.App&quot;,
                    deploymentTarget: .iOS(targetVersion: &quot;13.1&quot;, devices: [.iphone, .ipad]),
                    infoPlist: &quot;Info.plist&quot;,
                    sources: &quot;Sources/**&quot;)    </shiki-highlight>
  </div>
</div>
<h2 id="other-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other improvements<a href="#other-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other improvements"></a></h2>
<p>
This version of Tuist also includes some minor improvements to some existing features:</p>
<ul>
  <li>
<a href="https://github.com/tuist/tuist/pull/629"><strong>Made it fail when there are duplicated dependencies</strong></a>: We now detect if there are duplicated dependencies and fail early.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/578"><strong>Aligned packages API to SPM&#39;s</strong></a>: We refined the API for packages to be more alinged to the Swift Package Manager&#39;s.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/630"><strong>Added support for multiple Tuist directories</strong></a>: We added support for having multiple <code class="inline">Tuist</code> directories, which comes handy for large workspaces.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/546"><strong>Fixed false potivies detecting circular dependencies</strong></a>: We revisited the logic that detects circular dependencies because it was throwing some false positives.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/664"><strong>Fixed issue with dependencies in hosted unit test targets</strong></a>: Fixed duplicated symbols issues that showed up as a result of including transitive dependencies unnecessarily.  </li>
  <li>
<a href="https://github.com/tuist/tuist/pull/661"><strong>Added mising LD_RUNPATH_SEARCH_PATHS build setting to targets</strong></a>: Test targets were not getting the build setting set and that was causing test runs to fail.  </li>
</ul>
<h2 id="what's-coming" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s coming<a href="#what's-coming" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's coming"></a></h2>
<p>
We are working on adding support for <a href="https://ppinera.es/2019/10/10/manifest-helpers/">Project description helpers</a> that will allow developers to extract reusable pieces of their manifests into a separate framework that their manifest files can import. Moreover, we&#39;ll make the API of <code class="inline">ProjectDescription</code> ABI stable to prevent future Swift versions from breaking Tuist local installations. We also started working on a web service for Tuist users, Galaxy, that will provide Tuist users with insights and caching.</p>
<p>
Stay tuned because you have not yet seen everything Tuist has to offer you!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Welcome Swift Packages to the dependencies family in Tuist 0.18.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Marek Fořt ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Making the definition of dependencies very convenient was one of our aims when we embarked on building Tuist and today, we are extending that convenience to external dependencies that are distributed as Swift Packages. Targets can now define packages as dependencies and Tuist will take care of the rest. Moreover, this version ships with improvements in the API of dynamic Info.plist files. ]]></summary>
      <link href="https://tuist.dev/blog/2019/09/29/version-0180"/>
      <id>https://tuist.dev/blog/2019/09/29/version-0180</id>
      <updated>Sun, 29 Sep 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hey everyone 👋</p>
<p>
This is my first release and I am really excited to tell you what&#39;s new in this new 0.18.0 version of Tuist that brings Xcode 11 and Swift Package Manager support along with other great improvements.</p>
<p>
Let&#39;s begin and let me show you what&#39;s changed!</p>
<h2 id="new-infoplist.extendingdefault-case-📝" tabindex="-1" class="marketing__blog_post__body__content__heading">
New InfoPlist.extendingDefault case 📝<a href="#new-infoplist.extendingdefault-case-📝" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to New InfoPlist.extendingDefault case 📝"></a></h2>
<p>
Tuist already supported passing the content of the target&#39;s Info.plist to the manifest. However, the whole content needed to be included in the dictionary, providing no benefit to the user compared to having the content in an <code class="inline">Info.plist</code> file.</p>
<p>
So, if you want to leverage the base values that Tuist provides for your <code class="inline">Target</code> and only extend it with a few optional arguments, now you can!</p>
<p>
To use this feature just define your dictionary in <code class="inline">.extendingDefault([:])</code> as in example:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
Target(name: &quot;App&quot;,
       platform: .iOS,
       product: .app,
       bundleId: &quot;io.tuist.App&quot;,
       // Defining custom values for `Info.plist`
       infoPlist: .extendingDefault(with: [
           &quot;CFBundleShortVersionString&quot;: &quot;3.2.1&quot;
        ]),
       sources: &quot;Sources/**&quot;)    </shiki-highlight>
  </div>
</div>
<h2 id="multiline-settings-⚙️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Multiline settings ⚙️<a href="#multiline-settings-⚙️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Multiline settings ⚙️"></a></h2>
<p>
We have made a small change in how we handle <code class="inline">Settings</code> because Xcode could sometimes create unepexcted diff from the version created by <code class="inline">tuist</code>.</p>
<p>
To fix this, defining the <code class="inline">base</code> parameter has been changed from <code class="inline">[String: String]</code> to <code class="inline">[String: SettingValue]</code>, so we can handle the order of arguments leveraging <code class="inline">ExpressibleByStringLiteral</code> protocol.</p>
<p>
The <code class="inline">Settings</code> should now be declared like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Explicitly define the type of value for `settings`
let settings: [String: SettingValue] = [&quot;WARNING_CFLAGS&quot;: &quot;VALUE&quot;]
let targetSettings = Settings(
  base: settings,
  configurations: [],
  defaultSettings: .recommended
)    </shiki-highlight>
  </div>
</div>
<p>
You can find more info <a href="https://github.com/tuist/tuist/pull/464#issuecomment-529673717">here</a>.</p>
<h2 id="swift-package-manager-support-📦" tabindex="-1" class="marketing__blog_post__body__content__heading">
Swift Package Manager Support 📦<a href="#swift-package-manager-support-📦" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Swift Package Manager Support 📦"></a></h2>
<p>
At this year&#39;s WWDC, we finally got SPM&#39;s support in Xcode, so that&#39;s something that we needed to support, too, alongside Carthage and Cocoapods. And finally, you can easily define SPM dependencies easily in your <code class="inline">Project.swift</code> manifest! We have tried to make a declaration of a package dependency as similar as we could to how they are defined in SPM&#39;s manifest <code class="inline">Package.swift</code>.</p>
<p>
SPM provides remote packages (either from git remote repositories like Github or remote repository from your file system) and local which are best suited when you first want to incorporate the package in your project and build it alongside it before possibly finalizing and moving it to a project of its own.</p>
<p>
So, below is an example of how you could add a remote and a local package to a <code class="inline">Target</code> of your choosing:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
Target(name: &quot;App&quot;,
       platform: .iOS,
       product: .app,
       bundleId: &quot;io.tuist.App&quot;,
       sources: [&quot;Sources/**&quot;],
       dependencies: [
            .package(url: &quot;https://github.com/ReactiveX/RxSwift&quot;, productName: &quot;RxSwift&quot;, .upToNextMajor(from: &quot;5.0.0&quot;)),
            .package(url: &quot;https://github.com/tuist/XcodeProj&quot;, productName: &quot;xcodeproj&quot;, from: &quot;6.7.0&quot;),
            .package(url: &quot;https://github.com/tuist/shell&quot;, productName: &quot;shell&quot;, &quot;2.1.2&quot;..&lt;&quot;2.2.0&quot;),
            .package(path: &quot;RelativePath/ToYourPackage&quot;, productName: &quot;PackageLibrary&quot;),
       ]),    </shiki-highlight>
  </div>
</div>
<p>
If you are familiar with <code class="inline">Package.swift</code>, there should be almost no learning curve! Now there are no more obstacles to adding a package to your project 🥳</p>
<p>
Also note that this will add <code class="inline">.package.resolved</code> file to your root directory to enable your team to use the same version for every package without commiting your workspace. <code class="inline">tuist</code> handles this file for you, so you don&#39;t have to worry about it.</p>
<h2 id="other-improvements-⭐️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other improvements ⭐️<a href="#other-improvements-⭐️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other improvements ⭐️"></a></h2>
<h3 id="xcode-11-support-🛠" tabindex="-1" class="marketing__blog_post__body__content__heading">
Xcode 11 support 🛠<a href="#xcode-11-support-🛠" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Xcode 11 support 🛠"></a></h3>
<p>
Now, you can comfortably contribute to Tuist with Xcode 11! This release is the first one that has been built with a new Xcode, so you can finally delete the old one.</p>
<h3 id="codesign-output-🔑" tabindex="-1" class="marketing__blog_post__body__content__heading">
Codesign output 🔑<a href="#codesign-output-🔑" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Codesign output 🔑"></a></h3>
<p>
To have better understanding of what&#39;s happening when running codesigning, we now include the output of this command to the command line.</p>
<h2 id="bug-fixes-🐛" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug fixes 🐛<a href="#bug-fixes-🐛" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug fixes 🐛"></a></h2>
<ul>
  <li>
Transitively link static dependency&#39;s dynamic dependencies correctly  </li>
  <li>
Prevent embedding static frameworks  </li>
  <li>
Output losing its format when tuist is run through tuistenv  </li>
  <li>
Product name linting failing when it contains variables  </li>
  <li>
Build phases not generated in the right position  </li>
</ul>
<h2 id="changelog" tabindex="-1" class="marketing__blog_post__body__content__heading">
Changelog<a href="#changelog" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Changelog"></a></h2>
<p>
You can check out the complete changelog <a href="https://github.com/tuist/tuist/blob/main/CHANGELOG.md">here</a>.</p>
<h3 id="personal-note" tabindex="-1" class="marketing__blog_post__body__content__heading">
Personal note<a href="#personal-note" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Personal note"></a></h3>
<p>
I want to thank all the people working on Tuist - working on SPM support has been a great deal of fun thanks to the community that has evolved around the project. So, if there is something that you want to improve in Tuist, definitely consider creating a PR, you won&#39;t regret it!</p>
<p>
Also do not be afraid to ask for additional guidance in our <a href="https://slack.tuist.io">Slack channel</a>, I am sure someone will help you out.</p>
<p>
Anyway, thanks for reading and see you at the next release!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Visualize your projects graph from Tuist 0.17.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ One of the difficulties of scaling up Xcode projects comes from the fact that Xcode doesn't provide a high-level picture of the structure of the project. Tuist 0.17.0 fixes that by providing a new command, 'tuist graph', that exports a graph of the project to help users of the tool visualize their project dependencies. This version also adds support for configuring Tuist globally, and also indicate the version of Xcode that is required to run the project. ]]></summary>
      <link href="https://tuist.dev/blog/2019/08/14/version-0170"/>
      <id>https://tuist.dev/blog/2019/08/14/version-0170</id>
      <updated>Wed, 14 Aug 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hola 👋</p>
<p>
Last week we released a new version of Tuist,
0.17.0,
which comes packed with a handful of great improvements that will make your experience interacting with your projects more pleasing.</p>
<p>
In this post,
I&#39;d like to guide you through some of those new features,
as well as showing you some minor improvements and bug fixes that we have also introduced.</p>
<p>
Let&#39;s get started.</p>
<h2 id="support-for-multiple-configurations-📝" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support for multiple configurations 📝<a href="#support-for-multiple-configurations-📝" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support for multiple configurations 📝"></a></h2>
<p>
It&#39;s a common practice to use build configurations to define variants for our apps other than <code class="inline">Debug</code> and <code class="inline">Release</code>.
Unfortunately,
Tuist only supported configuring <code class="inline">Debug</code> and <code class="inline">Release</code>,
and that was a limiting factor for some users to adopt Tuist.</p>
<p>
We have good news for you; with the latest version of Tuist, you can define all the configurations that your project needs:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let targetSettings = Settings(
  base: [:],
  configurations: [
    .debug(name: &quot;Debug&quot;, settings: [:], xcconfig: &quot;xcconfigs/Debug.xcconfig&quot;),
    .release(name: &quot;Release&quot;, settings: [:], xcconfig: &quot;xcconfigs/Release.xcconfig&quot;),

    // Beta build variant
    .release(name: &quot;Beta&quot;, settings: [:], xcconfig: &quot;xcconfigs/Beta.xcconfig&quot;),
  ],
  defaultSettings: .recommended
)
    </shiki-highlight>
  </div>
</div>
<h2 id="graph-🔀" tabindex="-1" class="marketing__blog_post__body__content__heading">
Graph 🔀<a href="#graph-🔀" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Graph 🔀"></a></h2>
<p>
When Xcode projects get larger,
being able to see how projects and targets depend on each other is handy to make decisions to extend the modularity of the project.
Moreover,
it makes it easier for newcomers to have a picture of the whole project without having to open Xcode and wander around.</p>
<p>
The usage is very simple.
Being in a directory that contains a project,
run the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
tuist graph    </shiki-highlight>
  </div>
</div>
<p>
That generates a <code class="inline">graph.dot</code> file that we can turn into a visual representation using <a href="https://www.graphviz.org/">Graphviz</a> or <a href="https://dreampuf.github.io/GraphvizOnline">this online tool</a>.</p>
<h2 id="global-configuration-📝" tabindex="-1" class="marketing__blog_post__body__content__heading">
Global configuration 📝<a href="#global-configuration-📝" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Global configuration 📝"></a></h2>
<p>
We are glad to welcome <code class="inline">TuistConfig.swift</code> to the family!
We realized that configuring Tuist for all the projects that are part of a repository was not possible and required having to pass argument when calling different tuist commands.
To make that easier we introduced the concept of a configuration that is globally applied to all the projects that are part of a repository.
Imagine we have the following folder structure:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
/.git
/TuistConfig.swift
/Core/Project.swift
/Settings/Project.swift
/App/Project.swift    </shiki-highlight>
  </div>
</div>
<p>
And the following content in the <code class="inline">TuistConfig.swift</code> file:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let config = TuistConfig(
  generationOptions: [
    .xcodeProjectName(&quot;MyCompany-\(.projectName)&quot;)
  ]
)    </shiki-highlight>
  </div>
</div>
<p>
With the configuration above,
all the generated Xcode projects will follow the configured naming convention.</p>
<blockquote>
  <p>
Note how Swift and its powerful type system allows interpolating pre-defined variables into the strings.  </p>
</blockquote>
<h2 id="compatible-xcode-versions-✅" tabindex="-1" class="marketing__blog_post__body__content__heading">
Compatible Xcode versions ✅<a href="#compatible-xcode-versions-✅" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Compatible Xcode versions ✅"></a></h2>
<p>
<em>Have you ever tried to compile a project with an Xcode version that the project is not compatible with?</em>
It often results in compilation errors because the project hasn&#39;t been updated yet.
Xcode doesn&#39;t allow pinning a project to a specific Xcode version,
and thus when the OS updates Xcode automatically,
developers run into this issue.</p>
<p>
The latest version of Tuist allows defining a version or list of versions that your projects are compatible with.
We can do so by using the global configuration:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let config = TuistConfig(
  compatibleXcodeVersions: [&quot;11.3&quot;]
)    </shiki-highlight>
  </div>
</div>
<p>
If a developer in your team tries to use the project with a non-compatible version of Xcode,
Tuist will fail letting developers know why.</p>
<h2 id="cocoapods-support-📦" tabindex="-1" class="marketing__blog_post__body__content__heading">
CocoaPods support 📦<a href="#cocoapods-support-📦" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to CocoaPods support 📦"></a></h2>
<p>
In order to use CocoaPods with Tuist,
developers had to manually execute <code class="inline">pod install</code> right after the project generation.</p>
<p>
That&#39;s not necessary anymore because we&#39;ve added support for a new type of dependency, <code class="inline">.cocoapods</code>. Targets can use that type of dependency to indicate that <code class="inline">pod install</code> needs to be run after generating the project the target belongs to.</p>
<p>
Note that Tuist doesn&#39;t validate the right configuration of the <code class="inline">Podfile</code> nor makes sure that Tuist&#39;s dependency graph and CocoaPod&#39;s merge gracefully.
For that reason,
we suggest defining CocoaPods dependencies from the app targets and not from its dependencies.</p>
<h2 id="other-improvements-⭐️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Other improvements ⭐️<a href="#other-improvements-⭐️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Other improvements ⭐️"></a></h2>
<h3 id="productname-support" tabindex="-1" class="marketing__blog_post__body__content__heading">
productName support<a href="#productname-support" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to productName support"></a></h3>
<p>
Targets can now specify their product name without having to define a build setting for that:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let macosTarget = Target(name: &quot;CoremacOS&quot;, productName: &quot;Core&quot;)
let iosTarget = Target(name: &quot;CoreiOS&quot;, productName: &quot;Core&quot;)    </shiki-highlight>
  </div>
</div>
<h3 id="support-static-products-depending-on-dynamic-frameworks" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support static products depending on dynamic frameworks<a href="#support-static-products-depending-on-dynamic-frameworks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support static products depending on dynamic frameworks"></a></h3>
<p>
Before this version,
it was not possible to link a static product against a dynamic framework.
That&#39;s possible now.
As always,
Tuist will take care of defining the right build settings and phases for you.</p>
<h3 id="swift-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
Swift project<a href="#swift-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Swift project"></a></h3>
<p>
Tuist is now more integrated into the <code class="inline">swift</code> command line namespace.
Its command line interface is now available through the <code class="inline">swift project</code> namespace.
For example,
if you try to run <code class="inline">swift project init</code>,
It&#39;ll generate an empty project using Tuist.</p>
<h3 id="generate-a-single-project" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generate a single project<a href="#generate-a-single-project" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generate a single project"></a></h3>
<p>
By default,
<code class="inline">tuist generate</code> generates all the projects that are part of the dependency graph.
However,
there are some scenarios where the users might just be interested in generating the project in the current directory.
For that reason,
we added support for generating only the project in the current directory.</p>
<p>
It&#39;s as easy as passing the <code class="inline">--project-only</code> argument to the generate command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate --project-only    </shiki-highlight>
  </div>
</div>
<h3 id="support-for-multiple-header-globs" tabindex="-1" class="marketing__blog_post__body__content__heading">
Support for multiple header globs<a href="#support-for-multiple-header-globs" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Support for multiple header globs"></a></h3>
<p>
Before this version,
it was only possible to specify the headers that were part of a target by passing a string with a glob pattern.
This was limiting so we made it more flexible by supporting a list of patterns:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let headers = Headers(public: [&quot;Headers/**/*.h&quot;, &quot;Other/**/*.h&quot;])    </shiki-highlight>
  </div>
</div>
<h2 id="bug-fixes-🐛" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug fixes 🐛<a href="#bug-fixes-🐛" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug fixes 🐛"></a></h2>
<p>
This release also fixes bugs that have been detected and reported by users:</p>
<ul>
  <li>
Ensure that transitive SDK dependencies are added correctly.  </li>
  <li>
Ensure that the correct platform SDK dependencies path is set.  </li>
  <li>
Update manifest target name such that its product has a valid name.  </li>
  <li>
Do not create Derived/InfoPlists folder when no InfoPlist dictionary is specified.  </li>
  <li>
Set the correct <code class="inline">lastKnownFileType</code> for localized files.  </li>
</ul>
<h2 id="some-final-words" tabindex="-1" class="marketing__blog_post__body__content__heading">
Some final words<a href="#some-final-words" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Some final words"></a></h2>
<p>
I&#39;m tremendously grateful to all the maintainers and contributors that made this release possible without breaking changes, and putting emphasis into the simplicity and sustainability of the codebase.</p>
<p>
We look forward to your feedback; it&#39;s very valuable for us to keep improving Tuist to address the needs and challenges you face in the problem of scaling app Xcode projects.</p>
<p>
Remember,
you can join our <a href="https://slack.tuist.io">Slack channel</a> and talk to another users that are already benefiting from Tuist in their projects.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 0.16.0 allows users to link system libraries and frameworks ]]></title>
      
      
      <author>
        <name><![CDATA[ Oliver Atkinson ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ From the just released 0.16.0 version of Tuist, users will be able to define dependencies with system libraries and frameworks from their targets. Moreover, we added support for customizing the list of input and output files in their target action, and generation of targets with no build settings at all. This version also ships with minor improvements and bug fixes that had been reported by users. ]]></summary>
      <link href="https://tuist.dev/blog/2019/06/21/version-0160"/>
      <id>https://tuist.dev/blog/2019/06/21/version-0160</id>
      <updated>Fri, 21 Jun 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Hi, Ollie here 👋🏼! Happy Friday!</p>
<p>
I&#39;m happy to announce the release of Tuist 0.16.0; I&#39;m going to talk through the changes we have made this release and some of the upcoming work we have planned to support some of the newer features announced at this year&#39;s WWDC.</p>
<h2 id="adding-support-for-linking-system-libraries-and-frameworks-🏛" tabindex="-1" class="marketing__blog_post__body__content__heading">
Adding support for linking system libraries and frameworks 🏛<a href="#adding-support-for-linking-system-libraries-and-frameworks-🏛" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Adding support for linking system libraries and frameworks 🏛"></a></h2>
<p>
Liking against system libraries and frameworks explicitly is sometimes necessary. This is a common use-case when using 3rd-Party frameworks such as Firebase.</p>
<p>
We&#39;ve <a href="https://docs.old.tuist.io/usage-3-dependencies#system-libraries-and-frameworks-dependencies">added support</a> for a new dependency type <code class="inline">sdk</code>.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
Target(
    name: &quot;App&quot;,
    platform: .iOS,
    product: .app,
    bundleId: &quot;io.tuist.App&quot;,
    infoPlist: &quot;Info.plist&quot;,
    sources: [ &quot;Sources/**&quot; ],
    dependencies: [
        .sdk(name: &quot;CloudKit.framework&quot;, status: .required),
        .sdk(name: &quot;StoreKit.framework&quot;, status: .optional),
        .sdk(name: &quot;libc++.tbd&quot;),
    ]
)    </shiki-highlight>
  </div>
</div>
<h2 id="add-input-&-output-paths-for-target-action-🎯" tabindex="-1" class="marketing__blog_post__body__content__heading">
Add input &amp; output paths for target action 🎯<a href="#add-input-&-output-paths-for-target-action-🎯" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Add input & output paths for target action 🎯"></a></h2>
<p>
If you use tools which need the ability to configure a pre-build or post-build script with input and output files, we now <a href="https://docs.old.tuist.io/usage-2-manifest#target-action">have added support for both</a>.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
.pre(
    path: &quot;my_custom_script.sh&quot;,
    name: &quot;My Custom Script Phase&quot;,
    inputFileListPaths: [ &quot;Data/Cars.raw.json&quot;, &quot;Data/Drivers.raw.json&quot; ],
    outputFileListPaths: [ &quot;Data/Cars.swift&quot;, &quot;Data/Drivers.swift&quot; ]
)    </shiki-highlight>
  </div>
</div>
<h2>
Generate Tuist projects with <em>no</em> build settings 🧬</h2>
<p>
If you have a custom setup and don&#39;t want Tuist to provide any default build settings then <a href="https://docs.old.tuist.io/usage-2-manifest#settings">you are now able to specify</a> <code class="inline">.none</code> for <code class="inline">settings</code> on <code class="inline">Project</code> or <code class="inline">Target</code>.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let project = Project(
    name: &quot;MyFramework&quot;,
    settings: Settings(
        debug: .init(xcconfig: &quot;Configuration/Debug.xcconfig&quot;),
        release: .init(xcconfig: &quot;Configuration/Release.xcconfig&quot;),
        defaultSettings: .none
    ),
    targets: [
        Target(
            name: &quot;MyFramework&quot;,
            platform: .iOS,
            product: .framework,
            bundleId: &quot;io.tuist.MyFramework&quot;,
            infoPlist: &quot;Sources/Info.plist&quot;,
            sources: [
                &quot;Sources/**&quot;
            ],
            dependencies: [
                .framework(path: &quot;../Framework2/prebuilt/Framework2.framework&quot;),
            ]
        ),
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
This will ensure tuist does not generate a project with <em>any</em> build settings. Be warned if you do this you will need to ensure you provide some build settings otherwise it might not build inside Xcode.</p>
<h2 id="bug-fixes-🐞" tabindex="-1" class="marketing__blog_post__body__content__heading">
Bug Fixes 🐞<a href="#bug-fixes-🐞" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Bug Fixes 🐞"></a></h2>
<p>
We&#39;ve been really busy squishing bugs and improving the overall stability and experience when using Tuist. We think fixing bugs you find are very important to us and the future of Tuist - so if you find any bugs please <a href="https://github.com/tuist/tuist/issues/new/choose">raise an issue</a>.</p>
<h3 id="code-sign-frameworks-on-when-embedding-✍🏼" tabindex="-1" class="marketing__blog_post__body__content__heading">
Code sign frameworks on when embedding ✍🏼<a href="#code-sign-frameworks-on-when-embedding-✍🏼" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Code sign frameworks on when embedding ✍🏼"></a></h3>
<p>
Frameworks were not correctly being codesigned when embedded. This caused a bug when trying to build to device &quot;App installation failed. No code signature found&quot;. I was able to figure out where the problem was and <a href="https://github.com/tuist/tuist/pull/398">include it in this release</a>. Thanks to @Rag0n for rasising the issue.</p>
<h3 id="stability-for-generated-projects-🏗" tabindex="-1" class="marketing__blog_post__body__content__heading">
Stability for generated projects 🏗<a href="#stability-for-generated-projects-🏗" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Stability for generated projects 🏗"></a></h3>
<p>
We&#39;ve been working really hard to <a href="https://github.com/tuist/tuist/pull/410">stabilize</a> the generated Xcode projects which is really good news if you check them in as you will not see changes you didn&#39;t intend to make. It also meant that Xcode could not live-reload the project correctly.</p>
<p>
Both Kas and Marcing have introduced fixes into this release! 💪🏼</p>
<h3 id="installing-custom-tuist-builds-from-source-👷🏼‍♂️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Installing custom tuist builds from source 👷🏼‍♂️<a href="#installing-custom-tuist-builds-from-source-👷🏼‍♂️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Installing custom tuist builds from source 👷🏼‍♂️"></a></h3>
<p>
<code class="inline">tuist local</code> was failing to install due to a small bug in the installer still referencing an old compiler flag, luckily I was able to track down the issue and <a href="https://github.com/tuist/tuist/pull/402">fix it</a>. So if you like living on the edge and using the <code class="inline">main</code> branch then it&#39;s all back up and working 👍🏼</p>
<h3>
And much much more, <a href="https://github.com/tuist/tuist/blob/main/CHANGELOG.md">checkout the changelog</a> for the full list of additions, fixes and improvements</h3>
<h2 id="next-up-🕵🏼‍♂️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Next up 🕵🏼‍♂️<a href="#next-up-🕵🏼‍♂️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Next up 🕵🏼‍♂️"></a></h2>
<ul>
  <li>
We <a href="https://github.com/tuist/tuist/pull/394">have started work</a> on adding support for SwiftPM.  </li>
  <li>
Tuist will soon <a href="https://github.com/tuist/tuist/pull/380">be able to control</a> the generation of the Info.plist for your project/manifest.  </li>
  <li>
You will soon <a href="https://github.com/tuist/tuist/pull/382">be able to visualise</a> your dependencies.  </li>
  <li>
Join the discussion about <a href="https://github.com/tuist/tuist/issues/401">how we could support the new <code class="inline">.xcframework</code> type</a>.  </li>
  <li>
We&#39;re talking about <a href="https://github.com/tuist/tuist/issues/397">multi-platform targets</a>.  </li>
</ul>
<p>
Thanks, see you next time!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Dynamically generated Info.plist files with Tuist 0.15.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist 0.15.0 extend the beauty of generation to Info.plist. From this version on you'll be able to define the build settings as part of your manfest and let Tuist infer the default values for you. Furthermore, we extended the API to support customizing the generation of default build settings in your projects and targets, added the generation time to the 'tuist generate' command, and added support for defining custom schemes. ]]></summary>
      <link href="https://tuist.dev/blog/2019/06/02/version-0150"/>
      <id>https://tuist.dev/blog/2019/06/02/version-0150</id>
      <updated>Sun, 02 Jun 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist 0.15.0 has <a href="https://github.com/tuist/tuist/releases/tag/0.15.0">been been released</a>; just in time for WWDC. On this blog post, I&#39;d like to go through the major updates that come with this version.</p>
<p>
If you are in San Jose during WWDC and would like to meet to chat about Tuist and Xcode at scale, let us know. Understanding how other projects use Xcode and structure their project is very valuable to improve the tool and abstract you from Xcode intricacies. I&#39;ll also be speaking at AltConf on Thursday so come and say hola 👋.</p>
<h2 id="default-settings-⚙️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Default settings ⚙️<a href="#default-settings-⚙️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Default settings ⚙️"></a></h2>
<p>
<a href="https://github.com/tuist/tuist/pull/373">Pull request</a></p>
<p>
Tuist used to generate the projects and targets with some default build settings. Although that worked for most of the projects, some projects wanted to have more control over that. The new version of Tuist supports passing a new attribute to the <code class="inline">Settings</code> model, <code class="inline">defaultSettings</code>. It can take any of the following values:</p>
<ul>
  <li>
<em>.recommended:</em> Recommended settings including warning flags to help you catch some of the bugs at the early stage of development.  </li>
  <li>
<em>.essential:</em> A minimal set of settings to make the project compile without any additional settings for example <code class="inline">PRODUCT_NAME</code> or <code class="inline">TARGETED_DEVICE_FAMILY</code>.  </li>
</ul>
<p>
This change is backwards-compatible by defaulting to <code class="inline">.recommended</code>. If you want Tuist not to generate any build settings, you can pass <code class="inline">nil</code> value.</p>
<h2 id="infoplist-📝" tabindex="-1" class="marketing__blog_post__body__content__heading">
InfoPlist 📝<a href="#infoplist-📝" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to InfoPlist 📝"></a></h2>
<p>
<a href="https://github.com/tuist/tuist/pull/378">Pull request</a></p>
<p>
As you might already know, targets require an <em>Info.plist</em> file to be set. The content of the <em>Info.plist</em> files is almost identical with the exception of some attributes that are specific to the target, like the launch storyboard or the build and version numbers. Although the cost of maintenance of those files is not that high, we believe Tuist can do that work for the developer and take the opportunity to run some validations to prevent future compilation errors.</p>
<p>
In that regard, in the new version of Tuist we&#39;ve turned the <code class="inline">infoPlist</code> attribute of <code class="inline">Target</code> from <code class="inline">String</code> into its own model, <code class="inline">InfoPlist</code>. Although the change makes no difference for now, we are working on letting the developers pass some ownership of those files to Tuist. In the next version of Tuist developers will be able to define the Info.plist content by using the following values:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
InfoPlist.dictionary([&quot;CFBundleIdentifier&quot;, &quot;io.tuist.MyApp&quot;])

// Extends a base list of attributes
InfoPlist.base(extend: [&quot;CFBundleIdentifier&quot;, &quot;io.tuist.MyApp&quot;])    </shiki-highlight>
  </div>
</div>
<h2 id="generation-time-⌚️" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generation time ⌚️<a href="#generation-time-⌚️" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generation time ⌚️"></a></h2>
<p>
<a href="https://github.com/tuist/tuist/pull/335">Pull request</a></p>
<p>
With developers introducing Tuist into their workflows, the generation of projects <strong>must be fast.</strong> If you would like to know how much it takes, the new version of Tuist prints the total generation time:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
$ tuist generate

Generating workspace App.xcworkspace
Generating project App
✅ Success: Project generated.
Total time taken: 0.605s    </shiki-highlight>
  </div>
</div>
<h2 id="schemes-📱" tabindex="-1" class="marketing__blog_post__body__content__heading">
Schemes 📱<a href="#schemes-📱" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Schemes 📱"></a></h2>
<p>
<a href="https://github.com/tuist/tuist/pull/336">Pull request</a></p>
<p>
Until this version, developers were not able to customize the list of generated schemes. That has changed and now schemes are configurable. When schemes are not passed, Tuist generates a default scheme for each target that is part of the project. The example below shows how schemes are initialized and used from a project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let scheme = Scheme(
    name: &quot;MyScheme&quot;,
    shared: true,
    buildAction: BuildAction(targets: [&quot;App&quot;]),
    testAction: TestAction.targets([&quot;AppTests&quot;]),
    runAction: RunAction(executable: &quot;App&quot;)
)

let project = Project(
    name: &quot;App&quot;,
    schemes: [scheme]
)    </shiki-highlight>
  </div>
</div>
<h2 id="compiler-flags-🚩" tabindex="-1" class="marketing__blog_post__body__content__heading">
Compiler flags 🚩<a href="#compiler-flags-🚩" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Compiler flags 🚩"></a></h2>
<p>
<a href="https://github.com/tuist/tuist/pull/386">Pull request</a></p>
<p>
Although it&#39;s not a commonly-used feature in Xcode, Tuist didn&#39;t support setting compiler flags to source files. With this new version, you can now pass flags alongside the source files:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let target = Target(sources: [.init(&quot;Sources/**/*.m&quot;, compilerFlags: &quot;my flag&quot;)])    </shiki-highlight>
  </div>
</div>
<h2 id="minor-fixes-and-improvements-🧪" tabindex="-1" class="marketing__blog_post__body__content__heading">
Minor fixes and improvements 🧪<a href="#minor-fixes-and-improvements-🧪" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Minor fixes and improvements 🧪"></a></h2>
<ul>
  <li>
We <a href="https://github.com/tuist/tuist/pull/357">fixed</a> a bug that caused the generation of projects to output Xcode projects with different format.  </li>
  <li>
Code sign on copy is now <a href="https://github.com/tuist/tuist/pull/333">set to true</a> by default for the frameworks in the &quot;Embed Frameworks&quot; build phase.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/338">fixed</a> a bug that caused files being added as folders.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/339">fixed</a> the template that we use to initialize projects so that it doesn&#39;t throw warnings.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/363">fixed</a> an issue that caused localized resources to be duplicated in the project.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/360">fixed</a> the lint check that raised warnings when targets linked static products.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/374">ensured</a> that bundle dependencies are properly configured for Xcode to build them beforehand.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/348">added support</a> for bundle dependencies that are part of other projects.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/356">added a check</a> to make sure that only headers are being added to the generated headers build phase.  </li>
</ul>
<h2 id="what's-next-🤔" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s next 🤔<a href="#what's-next-🤔" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's next 🤔"></a></h2>
<p>
At WWDC, Xcode support for Swift Package Manager was announced. We are excited to see Apple taking those steps and we&#39;d like Tuist to embrace the change and integrate with it. We started working on <a href="https://github.com/tuist/xcodeproj/pull/439">supporting</a> the changes to the Xcode project format with the goal of supporting defining packages as dependencies of your Tuist projects. This is how the integration might look:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let target = Target(dependencies: [.package(&quot;https://github.com/tuist/xcodeproj&quot;, .exact(&quot;1.2.3&quot;))])    </shiki-highlight>
  </div>
</div>
<p>
Stay tuned!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Workspace improvements with Tuist 0.13.0 ]]></title>
      
      
      <author>
        <name><![CDATA[ Kas Wridan ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ The just baked new version of Tuist, 0.13.0, is already with us. We added significant improvements to workspaces like being able to define additional files that are added to the project. We also aligned the structured of the generated workspaces to match the filesystem. This version also makes sure that for those test targets that depend on a host application are set up with the right settings. ]]></summary>
      <link href="https://tuist.dev/blog/2019/04/03/version-0130"/>
      <id>https://tuist.dev/blog/2019/04/03/version-0130</id>
      <updated>Wed, 03 Apr 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Tuist 0.13.0 has been released! 🎉</p>
<p>
We’re taking turns releasing and writing about what’s new in the world of Tuist. I’m Kas and will be your host through this post on the latest developments.</p>
<h2 id="contributors" tabindex="-1" class="marketing__blog_post__body__content__heading">
Contributors<a href="#contributors" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Contributors"></a></h2>
<p>
In this release Tuist gained a new contributor! <a href="https://github.com/BalestraPatrick">@BalestraPatrick</a> fixed a warning in newly generated projects <a href="https://github.com/tuist/tuist/pull/291">#291</a>. Additionally, <a href="https://github.com/pepicrft">@pepicrft</a> and <a href="https://github.com/ollieatkinson">@ollieatkinson</a> have been hard at work blitzing through numerous bug fixes and improvements 👏.</p>
<p>
Contributions also come in the form of valuable feedback, a huge shout out to <a href="https://github.com/enhorn">@enhorn</a> for actively reporting <a href="https://github.com/tuist/tuist/issues?utf8=✓&q=is%3Aissue+author%3Aenhorn+">issues and suggestions</a> to enhance Tuist.</p>
<p>
We’re really grateful for all the community contributions to improving Tuist!</p>
<h2 id="what’s-new?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s new?<a href="#what’s-new?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s new?"></a></h2>
<p>
The latest update can be obtained via running:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist update    </shiki-highlight>
  </div>
</div>
<p>
The full changelog can be viewed on the <a href="https://github.com/tuist/tuist/releases/tag/0.13.0">0.13.0 release page</a>. Here are some highlights.</p>
<h2 id="homebrew-tap-support" tabindex="-1" class="marketing__blog_post__body__content__heading">
Homebrew tap support<a href="#homebrew-tap-support" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Homebrew tap support"></a></h2>
<p>
The <code class="inline">Setup.swift</code> manifest now supports brew tap!</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let setup = Setup([
    .homebrewTap(repositories: [&quot;peripheryapp/periphery&quot;])
])    </shiki-highlight>
  </div>
</div>
<p>
Calling <code class="inline">tuist up</code> will ensure the tap is added to Homebrew.</p>
<h2 id="workspace-improvements" tabindex="-1" class="marketing__blog_post__body__content__heading">
Workspace Improvements<a href="#workspace-improvements" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Workspace Improvements"></a></h2>
<p>
By default, calling <code class="inline">tuist generate</code> will create an Xcode workspace containing the current project and all its dependencies.</p>
<p>
New in 0.13.0, the generated Xcode workspace structure reflects the file system!</p>
<p>
Additionally, the <code class="inline">Workspace.swift</code> manifest has been enhanced to allow the inclusion of files and folder references that don’t necessarily belong to a particular project - your Documentation files can now be included!</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let workspace = Workspace(
    name: &quot;Workspace&quot;,
    projects: [
        &quot;App&quot;,
        &quot;Frameworks/**&quot;,
    ],
    additionalFiles: [
        &quot;Documentation/**&quot;,
        .folderReference(path: &quot;Website&quot;)
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
&lt;img class=&quot;posts__post-screenshot&quot;</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
 alt=&quot;Workspace with additional files and folder references&quot;
 src=&quot;/marketing/images/blog/2019/04/03/workspace-improvements.png&quot; /&gt;    </shiki-highlight>
  </div>
</div>
<h2 id="host-application-for-unit-&-ui-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
Host application for unit &amp; ui tests<a href="#host-application-for-unit-&-ui-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Host application for unit & ui tests"></a></h2>
<p>
Tuist now automatically sets the host &amp; target application for test targets that declare they depend on applications.</p>
<p>
For example take the following <code class="inline">Project.swift</code> manifest:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let project = Project(
    name: &quot;App&quot;,
    targets: [
        Target(name: &quot;App&quot;,
            platform: .iOS,
            product: .app,
            bundleId: &quot;io.tuist.App&quot;,
            infoPlist: &quot;Info.plist&quot;,
            sources: &quot;Sources/**&quot;
        ),
        Target(
            name: &quot;AppTests&quot;,
            platform: .iOS,
            product: .unitTests,
            bundleId: &quot;io.tuist.AppTests&quot;,
            infoPlist: &quot;Tests.plist&quot;,
            sources: &quot;Tests/**&quot;,
            dependencies: [
                .target(name: &quot;App&quot;),
            ]
        ),
        Target(
            name: &quot;AppUITests&quot;,
            platform: .iOS,
            product: .uiTests,
            bundleId: &quot;io.tuist.AppUITests&quot;,
            infoPlist: &quot;Tests.plist&quot;,
            sources: &quot;UITests/**&quot;,
            dependencies: [
               .target(name: &quot;App&quot;),
            ]
        )
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
The generated project will have the host and target application set to <strong>App</strong> for the unit and ui test targets.</p>
<p>
&lt;img class=&quot;posts__post-screenshot&quot;</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
 alt=&quot;Unit tests target with host application&quot;
 src=&quot;/marketing/images/blog/2019/04/03/unit-tests-host-application.png&quot; /&gt;    </shiki-highlight>
  </div>
</div>
<p>
&lt;img class=&quot;posts__post-screenshot&quot;</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="">
 alt=&quot;UI tests target with target application&quot;
 src=&quot;/marketing/images/blog/2019/04/03/ui-tests-target-application.png&quot; /&gt;    </shiki-highlight>
  </div>
</div>
<h2 id="what’s-next?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next?<a href="#what’s-next?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next?"></a></h2>
<ul>
  <li>
    <p>
<a href="https://github.com/tuist/tuist/issues/265">#265</a> Storyboard enhancements - adding the ability to automatically generate the appropriate storyboard files via <code class="inline">tuist init</code> as well as explicitly specifying them within the <code class="inline">Project.swift</code> manifest to include in the generated Xcode project.    </p>
  </li>
  <li>
    <p>
<a href="https://github.com/tuist/tuist/issues/160">#160</a> Multiple configurations - a few different options are being explored, such as environments or possibly even <code class="inline">include</code>s to help reduce repeated definitions.    </p>
  </li>
  <li>
    <p>
<a href="https://github.com/tuist/tuist/issues/316">#316</a> Xcode 10.2 &amp; Swift 5 support.    </p>
  </li>
</ul>
<p>
If you have any ideas or feedback on these items or any others, please feel free to reach out on <a href="https://github.com/tuist/tuist">GitHub</a> or <a href="http://slack.tuist.io">Slack</a>!</p>
<p>
Happy Xcoding 🛠!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 0.12.0 supports defining multiple sources and resources ]]></title>
      
      
      <author>
        <name><![CDATA[ Oliver Atkinson ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Following users's feedback, we have released a new version of Tuist, 0.12.0 that supports defining multiple sources and resources. Moreover, we added a new product type for those of you that would like to opt for static linking, and added generation of schemes with all the targets that are part of the project. This version also drops support for defining the manifests as a JSON file because Swift will pave our way to a better maintainability and reusability. ]]></summary>
      <link href="https://tuist.dev/blog/2019/03/12/version-0120"/>
      <id>https://tuist.dev/blog/2019/03/12/version-0120</id>
      <updated>Tue, 12 Mar 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
I’d first like to introduce myself to all of you reading, since you were probably all expecting Pedro!</p>
<p>
I’m <a href="https://github.com/ollieatkinson">ollieatkinson</a>, I am from the United Kingdom and have recently become a core contributor for Tuist. I am very passionate about building great tools. I have also spent 8 years building iOS apps and know how frustrating it can be to manage Xcode projects. Contributing to Tuist was a natural fit for me, because it’s a tool I want myself.</p>
<p>
I would also like to welcome <a href="https://github.com/kwridan">Kas</a> and <a href="https://github.com/marciniwanicki">Marcin</a> who have also joined the core team. They are doing some fantastic work improving the foundations of the tool. You can checkout some of their work looking at the <a href="https://github.com/tuist/tuist/pulls?q=is%3Apr+is%3Aclosed">closed pull request list</a></p>
<p>
Tuist is very active at the moment - we have had a fantastic set of contributions.</p>
<p>
I’d like to thank <a href="https://github.com/dangthaison91">dangthaison91</a> for his contribution to allow for an array of resources and sources inside the project manifest and I’d like to say thanks to <a href="https://github.com/steprescott">steprescott</a> for getting to grips with the tool and making some great first contributions (<a href="https://github.com/tuist/tuist/pull/269">Pull Request #269</a> &amp; <a href="https://github.com/tuist/tuist/pull/272">Pull Request #272</a>)!</p>
<h2 id="getting-the-update" tabindex="-1" class="marketing__blog_post__body__content__heading">
Getting the update<a href="#getting-the-update" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Getting the update"></a></h2>
<p>
Updating to the latest version of Tuist is easy, just run update:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist update    </shiki-highlight>
  </div>
</div>
<p>
I’ll review some of the changes which have been released, but for a full list please <a href="https://github.com/tuist/tuist/releases/tag/0.12.0">head over to the GitHub release page</a>.</p>
<h2 id="[resources]-and-[sources]" tabindex="-1" class="marketing__blog_post__body__content__heading">
[Resources] and [Sources]<a href="#[resources]-and-[sources]" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to [Resources] and [Sources]"></a></h2>
<p>
It really bugged us that it wasn’t possible to specify multiple different sources for code and resources. One of our use-cases was to store the xibs alongside the source code and the images/fonts inside of a different folder.</p>
<p>
We really hope you like our change to support arrays for both <code class="inline">sources</code> and <code class="inline">resources</code>.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
Target(name: &quot;App&quot;,
       platform: .iOS,
       product: .app,
       bundleId: &quot;io.tuist.App&quot;,
       infoPlist: &quot;Info.plist&quot;,
       sources: [&quot;Sources/**&quot;, &quot;OtherSources/**&quot;],
         resources: [&quot;Images/*.{pdf,png}&quot;, &quot;Fonts/*.ttf&quot;],
       dependencies: [
            .framework(path: &quot;framework&quot;)
        ])    </shiki-highlight>
  </div>
</div>
<p>
Don’t worry! We have ensured this change is backwards compatible so you don’t have to change anything if you don’t want to add more locations.</p>
<h2 id="⚡️-static-frameworks" tabindex="-1" class="marketing__blog_post__body__content__heading">
⚡️ Static Frameworks<a href="#⚡️-static-frameworks" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to ⚡️ Static Frameworks"></a></h2>
<p>
We previously added support for static libraries, but we’ve now taken a step further and added support for static frameworks. Just choose the <code class="inline">.staticFramework</code> Product type.</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
Target(name: &quot;MyAwesomeStaticFramework&quot;,
       platform: .iOS,
       product: .staticFramework,
       bundleId: &quot;io.tuist.MyAwesomeStaticFramework&quot;,
       infoPlist: &quot;Info.plist&quot;,
       sources: [&quot;Sources/**&quot;, &quot;OtherSources/**&quot;])    </shiki-highlight>
  </div>
</div>
<p>
Static frameworks are much like static libraries - they become part of the executable, and are statically linked to client apps. They offer a slight advantage as you are able to also bundle your header files inside of the framework.</p>
<p>
According to Apple’s WWDC 2016 Session on <a href="https://developer.apple.com/videos/play/wwdc2016/406/">Optimizing App Startup Time</a> , regardless of their size, having a large number of <a href="https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/OverviewOfDynamicLibraries.html#//apple_ref/doc/uid/TP40001873-SW1">dynamically linked libraries</a> slows down app launch time dramatically.</p>
<p>
So if you are building a large scale application and have issues with start up times, then going static is definitely something you should consider.</p>
<h2 id="generate-a-scheme-with-all-the-project-targets" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generate a scheme with all the project targets<a href="#generate-a-scheme-with-all-the-project-targets" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generate a scheme with all the project targets"></a></h2>
<p>
We will now generate you an extra scheme for each project.</p>
<p>
The scheme called xxx-Project <em>(<strong>xxx</strong>is the name of the project)</em> contains all the targets within the project. Moreover, it defines test actions for all the targets that represent test bundles.</p>
<p>
This change will make possible supporting the following commands:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
sh    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="sh">
tuist build all
tuist test all    </shiki-highlight>
  </div>
</div>
<p>
N.b. the above does not exist <em>yet</em> but if you’re interested in it, please let us know!</p>
<h2 id="removed-support-for-yaml-and-json-projects" tabindex="-1" class="marketing__blog_post__body__content__heading">
Removed support for YAML and JSON Projects<a href="#removed-support-for-yaml-and-json-projects" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Removed support for YAML and JSON Projects"></a></h2>
<p>
We ❤️ Swift, and to ensure we continue to bring you amazing features we thought it was best to remove support for YAML and JSON specifications!</p>
<p>
This is so that developers will have a consistent experience and get all the features they expect when writing code: syntax colouring, code completion (see picture), API documentation, and formatting tools.</p>
<p>
  <img src="https://user-images.githubusercontent.com/1382565/54312754-98771a80-45cf-11e9-8d1e-ce3c909fdc53.png" alt="auto-complete">
</p>
<h2 id="what’s-next?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What’s next?<a href="#what’s-next?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What’s next?"></a></h2>
<p>
We have a lot of great features being worked on at the moment. I’ll name a few:</p>
<ul>
  <li>
<strong>Configurations</strong> - If you work on an Xcode project with a fairly complex setup then you probably use custom configurations to organise your xcconfig files. This is something we have wanted to support in Tuist for a while. We are coming really close to finalising the feature - I’ve been working with the rest of the core team to come up with a solution, and <a href="https://github.com/marciniwanicki">Marcin</a> has taken the lead with some really promising prototypes. You can follow the conversation on the pull request: <a href="https://github.com/tuist/tuist/pull/238">Pull Request #238</a>  </li>
  <li>
<strong>Workspace Configuration</strong> - If you want to add extra files to your workspace, and you want your workspace to mirror your folder structure on disk then get ready! <a href="https://github.com/tuist/tuist/pull/262">It’s coming!</a>  </li>
  <li>
<strong>Improving support for bootstrapping projects with Storyboards</strong> - Storyboards are a great way to get started when building a new project, there’s some great work to enable them by default and out of the box. All you will have to do is <code class="inline">tuist init</code>. <a href="https://github.com/tuist/tuist/pull/269">Checkout the pull request</a>  </li>
  <li>
<strong>Unified Resource Access</strong> - We want support for specifying module resources, and introduces a consistent way of referring to them from the source code in the package. One of the fundamental principles behind Tuist is that modules should be as portable and client-agnostic as possible: in particular, packages should make as few assumptions as possible about the details of how they will be incorporated. For example, a package might in one case be built as a dynamic library or framework that is embedded into an application bundle, and might in another case be statically linked into the client executable. We will be starting to discuss this soon, so watch out on <a href="https://github.com/tuist/tuist/issues">Github</a> or <a href="http://slack.tuist.io/">head over to Slack</a>.  </li>
</ul>
<p>
Happy Xcoding 📝!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Tuist 0.11.0 has been released ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist 0.11.0 is out and it includes features like "tuist up" that help users configure their environment before working with the projects, or support for generating target schemes. This version also adds support for defining environment variables for targets, as well as some minor improvements and fixes. ]]></summary>
      <link href="https://tuist.dev/blog/2019/02/14/version-0110"/>
      <id>https://tuist.dev/blog/2019/02/14/version-0110</id>
      <updated>Thu, 14 Feb 2019 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Today I&#39;d like to announce a new version of Tuist, 0.11.0. It&#39;s been a while without releasing Tuist versions but we are getting back to speed and getting great contributions from the community <em>(more on this later)</em>. Although Tuist 0.11.0 was not baked with major features, it comes with a handful list of improvements and fixes, some of which I&#39;d like to briefly touch on this announcement blog post.</p>
<h2 id="setup.swift" tabindex="-1" class="marketing__blog_post__body__content__heading">
Setup.swift<a href="#setup.swift" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Setup.swift"></a></h2>
<p>
In the previous version we introduced a new API for projects to define the tasks that&#39;d need to be executed to configure the local environment for the project. In the effort of making Tuist&#39;s core more reusable for external projects <em>(you can read more about it <a href="https://github.com/tuist/tuist/issues/192">here</a></em>, <a href="https://github.com/kwridan">Kassem</a> and <a href="https://github.com/marciniwanicki">Marcin</a> extracted the definition of those tasks into another manifest file, <code class="inline">Setup.swift</code>. From now this version, the tasks will be defined in that file following the following syntax:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">

let setup = Setup([
  .homebrew(packages: [&quot;swiftlint&quot;])
])    </shiki-highlight>
  </div>
</div>
<p>
<strong>We made an exception here and introduced a breaking change in a minor release because this release wasn&#39;t a significant milestone for the project to justify a major release.</strong></p>
<h2 id="generation-of-target-schemes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generation of target schemes<a href="#generation-of-target-schemes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generation of target schemes"></a></h2>
<p>
Before this change, Tuist did not generate any schemes for the project targets. The ones listed in the project were generated automatically by Xcode. From this version, Tuist generates an scheme per target. Those schemes are not configurable yet, but is something that we might evaluate and potentially support. You can check out <a href="https://github.com/tuist/tuist/issues/199">this</a> and <a href="https://github.com/tuist/tuist/issues/195">this proposal</a> to follow the discussion.</p>
<h2 id="target-environment-variables" tabindex="-1" class="marketing__blog_post__body__content__heading">
Target environment variables<a href="#target-environment-variables" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Target environment variables"></a></h2>
<p>
Targets support a new attribute, <code class="inline">environment</code>. When passed, Tuist sets those environment variables in the scheme asociated to the target:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let target = Target(environment: [&quot;foo&quot;: &quot;bar&quot;])    </shiki-highlight>
  </div>
</div>
<h2 id="minor-bug-fixes" tabindex="-1" class="marketing__blog_post__body__content__heading">
Minor bug fixes<a href="#minor-bug-fixes" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Minor bug fixes"></a></h2>
<ul>
  <li>
<strong>Verify bundle identifiers:</strong> Have you tried to use emojis 🥘 in a bundle identifier? You might have probably noticed that Xcode is not happy about it, nor we are. Before Xcode spits out an error we implemented a validation that fails the command if we detect invalid characters in your bundle identifier.  </li>
  <li>
<strong>Init in non-empty directories:</strong> Before this fix, trying to initialize a project in a directory that already contains other files might have resulted in an error. We&#39;ve changed that so that the command hesitates to run if there are files in the directory.  </li>
</ul>
<h2 id="deprecations" tabindex="-1" class="marketing__blog_post__body__content__heading">
Deprecations<a href="#deprecations" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Deprecations"></a></h2>
<p>
A few versions back, we added support for manifests defined in a JSON and Yaml. Unfortunately, we&#39;ve decided not to give support for them anymore. Those formats have been marked as deprecated. You can continue using them but we encourage you to use default Swift format before the next version comes out.</p>
<h2 id="what's-coming?" tabindex="-1" class="marketing__blog_post__body__content__heading">
What&#39;s coming?<a href="#what's-coming?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to What's coming?"></a></h2>
<p>
Brace yourself because the next version of Tuist will will be an important milestone for the project:</p>
<ul>
  <li>
<strong>Proper support for static libraries:</strong> If you work on an Xcode project with several frameworks and libraries you might have noticed how painful and cumbersome it is to maintain such a setup. Did you ever tried to move from dynamic to static or the other way around? Not easy right? The good news is that <a href="https://github.com/ollieatkinson">Oliver</a> felt the pain as well and devised Tuist&#39;s support for transitive static dependencies. It&#39;ll even allow you to use assets with static libraries. You can follow up the work <a href="https://github.com/tuist/tuist/pull/210">here</a>.  </li>
  <li>
<strong>Reusable core libraries:</strong> <a href="https://github.com/kwridan">Kassem</a> and <a href="https://github.com/marciniwanicki">Marcin</a> would like to leverage and extend the powerful core of Tuist and are currently working on making all the logic for generating projects reusable and flexible. You&#39;ll be able to import Tuist&#39;s generation library and use it as you want.  </li>
  <li>
<strong>Build command:</strong> One of the goals that I had in mind when I undertook to build Tuist was providing a set of commands that are common when working on Xcode projects. One of those commands is build. I imagined myself entering a directory with an Xcode project and being able to type <code class="inline">tuist build</code> with no flags at all. Well, that&#39;s becoming real and it&#39;ll likely be in the next version of Tuist. Furthermore, I&#39;m building a <a href="https://github.com/tuist/tuist/pull/196">xcodebuild parser</a> that among others, it&#39;ll allow formatting the output from <code class="inline">xcodebuild</code> like the so popular <a href="https://github.com/xcpretty/xcpretty">xcpretty</a>.  </li>
</ul>
<p>
As always, you can easily update the version by just running the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist update    </shiki-highlight>
  </div>
</div>
<p>
Happy xcoding 📝!</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Announcing Tuist 0.10 and its new 'up' command ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn more about the newest version of Tuist which comes with a powerful and useful feature, a new 'tuist up' command. ]]></summary>
      <link href="https://tuist.dev/blog/2018/12/20/version-0100"/>
      <id>https://tuist.dev/blog/2018/12/20/version-0100</id>
      <updated>Thu, 20 Dec 2018 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
I&#39;m pleased to tell you more about the new release of Tuist, 0.10.0, which we have just <a href="https://github.com/tuist/tuist/releases/tag/0.10.0">released</a>. If you work with Xcode-based projects, you might have realized that most of them require you to run a few commands in your system to set it up before start working on the project. Those commands usually install project dependencies, tools like <a href="https://brew.sh">Homebrew</a>, <a href="https://github.com/carthage/carthage">Carthage</a>, <a href="https://github.com/realm/SwiftLint">Swiftlint</a>... The commands are usually documented in the project <code class="inline">README</code> file, and in some cases, automated into a a sort of bootstrap script.</p>
<p>
There are several drawbacks with that so common approach:</p>
<ul>
  <li>
✅ Those scripts are rarely tested, which means that they can break without you noticing it. It&#39;s usually your team next hire the one that stumbles upon the issue and has to fix it.  </li>
  <li>
📚If you have several projects, you end up with duplicated bootstrap logic all over the place.  </li>
  <li>
📦 Moreover, if you jump between projects, you&#39;ll find different conventions on how to configure the environment depending on the project.  </li>
</ul>
<p>
If you are already using Tuist or plan to use it, we&#39;ll make it easier for you. The new version of Tuist comes with a new command <code class="inline">tuist up</code> which allows projects define how the environment should be configure in order for the project to work. <em>Handy, isn&#39;t it?</em> Let me give you an example.</p>
<p>
Let&#39;s say that your project depends on swiftlint being available in the system, which can be installed with Homebrew. Traditionally, you&#39;d find something like this in the project <code class="inline">README</code>:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
md    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="md">
1. Clone the repository.
2. Install Homebrew if you don&#39;t have it installed.
3. Install swiftlint with `brew install swiftlint`.
4. A Bunch of other steps.    </shiki-highlight>
  </div>
</div>
<p>
With Tuist we simplify and standardize the process. All you need to know is that there&#39;s a command, <code class="inline">tuist up</code> that ensures your environment is properly configured to work on the project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist init
tuist up
tuist generate    </shiki-highlight>
  </div>
</div>
<p>
In order for Tuist to know what needs to be configured in the environment, projects can now specify a list of up commands:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
let project = Project(name: &quot;Downloads&quot;,
                      up: [
                        .homebrew(packages: [&quot;swiftlint&quot;]),
                        .custom(name: &quot;My Tool&quot;, meet: &quot;./install-mytool.sh&quot;, isMet: &quot;test mytool&quot;)
                      ])    </shiki-highlight>
  </div>
</div>
<p>
There are some predefined commands, like the homebrew&#39;s that you can see in the example above, and you can also define custom ones, where you just need to define how the environment gets configured, and how to verify that the environment is properly configured. Although the list of predefined commands is limited, we plan to add more in the future after we validate the feature and get some ideas from you.</p>
<p>
Besides adding up, which is an important milestone for Tuist, this version also comes with some minor improvements:</p>
<ul>
  <li>
The Playgrounds group <a href="https://github.com/tuist/tuist/pull/177">is no longer generated</a> in the Xcode project when the project has no playgrounds.  </li>
  <li>
We <a href="https://github.com/tuist/tuist/pull/178">added support</a> for <code class="inline">.cpp</code> and <code class="inline">.c</code> source files.  </li>
</ul>
<p>
One of Tuist goals is to make convenient the inconvenient and establish good conventions and practices to let developers focus on building their apps. Up is a remarkable step towards that goal and we can&#39;t be more excited to have it out there for you to try it out in your projects. I&#39;d like to give credits to my colleagues at <a href="https://shopify.com">Shopify</a>, who came up with the idea of the <code class="inline">up</code> command for one of our company-wide internal tools. They are a huge source of inspiration, not only for the <code class="inline">up</code> command but for how to design and build tools for developers.</p>
<p>
As always, don&#39;t hesitate to share your thoughts, feedback, critics and anything that comes to your mind.</p>
<p>
Until the next release 👋</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Version 0.9.0 published ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ In this blog post we talk about the changes that come with the recently published version 0.9.0. ]]></summary>
      <link href="https://tuist.dev/blog/2018/12/03/version-090"/>
      <id>https://tuist.dev/blog/2018/12/03/version-090</id>
      <updated>Mon, 03 Dec 2018 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
Today we have <a href="https://github.com/tuist/tuist/releases/tag/0.9.0">published the version 0.9.0</a> of Tuist. It&#39;s been a while without releasing updates but we are getting back to speed. Stay tuned because we are working on a lot of improvements and cool features to make your experience dealing with Xcode projects more enjoyable.</p>
<h2 id="files-and-groups-order" tabindex="-1" class="marketing__blog_post__body__content__heading">
Files and groups order<a href="#files-and-groups-order" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Files and groups order"></a></h2>
<p>
Files and groups were sorted alphabetically when the project was generated. That resulted in a non-standard sorting order as Igor reported on <a href="https://github.com/tuist/tuist/issues/140">this issue</a>. With 0.9.0, we&#39;ve changed the order to default to sort files before groups, and then sort them alphabetically.</p>
<p>
In our aim to define conventions and good practices in Xcode projects, we don&#39;t plan to make the sorting configurable. We believe that the order that we set in this version is navigatable and aligned with Xcode defaults.</p>
<h2 id="generation-of-both,-debug-and-release-configurations" tabindex="-1" class="marketing__blog_post__body__content__heading">
Generation of both, Debug and Release configurations<a href="#generation-of-both,-debug-and-release-configurations" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Generation of both, Debug and Release configurations"></a></h2>
<p>
Previous versions of Tuist generated only the Debug or the Release configuration <em>(depending on the flag that you passed when running the tool)</em>. We have changed that behavior to generate both configurations. That allows developers building for any of the configurations without having to regenerate the Xcode project. Thanks Robin for <a href="https://github.com/tuist/tuist/issues/159">reporting the issue</a>.</p>
<h2 id="more-reliability-through-acceptance-tests" tabindex="-1" class="marketing__blog_post__body__content__heading">
More reliability through acceptance tests<a href="#more-reliability-through-acceptance-tests" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to More reliability through acceptance tests"></a></h2>
<p>
Although this is not a user-facing feature, it has a huge impact in the reliability of the tool. Although we took seriously and covered most of the execution paths with unit test, they don&#39;t prevent common Tuist use cases from breaking at any time. In <a href="https://github.com/tuist/tuist/pull/166">this PR</a> we add Cucumber to the toolbox to define acceptance tests that will be executed on CI. If you are curious about how a Cucumber test looks, you can have a look at the test below:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
ruby    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="ruby">
Feature: Initialize a new project using Tuist
Scenario: The project is a compilable macOS application
Given that tuist is available
And I have have a working directory
When I initialize a macos application named Test
Then I generate the project
Then I should be able to build the scheme Test
Then I delete the working directory    </shiki-highlight>
  </div>
</div>
<p>
If any of the feature steps breaks, the test fails and we have to fix it before merging the changes into main. This brings more confidence when adding changes to the project, which is very handy for new project contributors.</p>
<h2 id="how-to-update" tabindex="-1" class="marketing__blog_post__body__content__heading">
How to update<a href="#how-to-update" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to How to update"></a></h2>
<p>
It&#39;s very easy, did you know that Tuist knows how to update itself? There&#39;s no need to depend on third-party tools to drive the update. Just run the following command in your terminal:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
ruby    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="ruby">
tuist update    </shiki-highlight>
  </div>
</div>
<p>
I hope you like the release and that keep reporting issues and ideas to help Xcode developers deliver stunning high-quality apps.</p>
<blockquote>
  <p>
Don&#39;t forget to listen to the <a href="https://soundcloud.com/samar_elsayed/florencethemachine_hunger">soundtrack</a> of this release.  </p>
</blockquote>
<p>
Have a wonderful week.</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Generate Carthage-compatible Xcode projects for your open source libraries ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Learn how you can leverage Tuist and the project generation to make the generation of Carthage-compatible projects more convenient and aligned with the approach other package managers follow. ]]></summary>
      <link href="https://tuist.dev/blog/2018/11/14/carthage-projects"/>
      <id>https://tuist.dev/blog/2018/11/14/carthage-projects</id>
      <updated>Wed, 14 Nov 2018 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
If you are o have been a maintainer of an open source Swift project, you might have realized how inconvenient it is giving support to all package managers out there: <a href="https://cocoapods.org/">CocoaPods</a>, <a href="https://github.com/carthage">Carthage</a> and the <a href="https://github.com/apple/swift-package-manager">Swift Package Manager</a>. Each of those package managers follows a different approach for defining the structure of your package. A Ruby <code class="inline">.podspec</code> file if it’s CocoaPods, a Swift <code class="inline">Package.swift</code> manifest in case of the Swift Package Manager and an Xcode project in Carthage.</p>
<p>
The latter is perhaps the most inconvenient. <strong>Any change in your project files need to be reflected in the Xcode project</strong>. Otherwise, you get a package ready for CocoaPods and Swift Package Manager, but that is broken for Carthage. Those changes are usually done manually, and projects set up the CI pipeline that compiles the Carthage project and makes sure that the integration doesn’t break.</p>
<p>
In this short blog post, I’d like to show you how we can make generating the Carthage project more convenient and aligned with the other package managers’ approach.</p>
<p>
To generate an Xcode project for Carthage, you need to have Tuist installed in your system. You can do it by just running the following command in your terminal:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
eval \&quot;\$(curl -sL https://bit.ly/2JWMfx8)\&quot;
    </shiki-highlight>
  </div>
</div>
<p>
Once installed, we need to generate a manifest <code class="inline">Project.swift</code> file in the project directory. You can look at that file as an equivalent to the <code class="inline">Package.swift</code> but more generic and valid for any type of Xcode project:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
// Project.swift
import ProjectDescription

let project = Project(name: &quot;MyProject-Carthage&quot;,
                      targets: [
                        Target(name: &quot;MyProject&quot;,
                               platform: .macOS,
                               product: .framework,
                               bundleId: &quot;io.tuist.MyProject&quot;,
                               infoPlist: &quot;Info.plist&quot;,
                               sources: &quot;Sources/MyProject/\*\*&quot;,
                               dependencies: [
                                  .framework(path: &quot;Carthage/Build/Mac/SwiftShell.framework&quot;)
                               ])
                              ]
)    </shiki-highlight>
  </div>
</div>
<p>
As you can see in the code snippet, a project has a name, which is the name of the Xcode project that will get generated, and a list of targets, which represent Xcode project targets. In that example, we are creating a framework for macOS with the name <code class="inline">MyProject</code>, and that compiles all the sources in the <code class="inline">Sources/MyProject/</code> recursively. Note that you can also include resources and specify custom build settings. You can check all the attributes that are available on [this link].</p>
<blockquote>
  <p>
You can define dependencies with other Carthage frameworks passing them in the <code class="inline">dependencies</code> attribute. Tuist will set up the linking build phase.  </p>
</blockquote>
<p>
With the manifest created in the project directory, we can run the following command:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate
    </shiki-highlight>
  </div>
</div>
<p>
It’ll generate the Xcode project automatically 🚀. <strong>The project generation is deterministic</strong>, that means that the same command executed several times should produce the same Xcode project. You can run that command as part of your CI and fail if the command results in a diff in the git repository. <a href="https://danger.systems">Danger</a> is a great tool to report the error back to GitHub and ask developers to re-generate the project and push the changes.</p>
<h3 id="shortcomings" tabindex="-1" class="marketing__blog_post__body__content__heading">
Shortcomings<a href="#shortcomings" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Shortcomings"></a></h3>
<ul>
  <li>
Tuist doesn’t support defining schemes yet <em>(but we are working on it)</em>. That means that you need to double check if the scheme that Xcode generates automatically is shared.  </li>
  <li>
If you want to support multiple platforms, you need a target per platform with the same name but with a different product name. Although you can change that by passing build settings, we plan to expose a new attribute in the <code class="inline">Target</code> model to make it more explicit.  </li>
</ul>
<h3 id="wrapping-up" tabindex="-1" class="marketing__blog_post__body__content__heading">
Wrapping up<a href="#wrapping-up" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to Wrapping up"></a></h3>
<p>
I hope you liked the blog post. As you can see, <strong>Tuist is opening the door to having more automation in your projects and saving a lot of time</strong> that you’d have spent tweaking the projects yourself. This is just a use case for Tuist, but there are many others. If you are eager to know more about what’s coming to Tuist, I recommend you to check out the <a href="https://github.com/orgs/tuist/projects/4">organization roadmap</a>.</p>
<p>
Can’t wait to share more with you soon! 👩‍💻</p>
 ]]></content>
    </entry>
  
    <entry>
      <title><![CDATA[ Introducing Tuist ]]></title>
      
      
      <author>
        <name><![CDATA[ Pedro Piñera ]]></name>
      </author>
      
      <summary type="html"><![CDATA[ Tuist was oficially released. Read more on this blog post about what motivated us to build Tuist and how it can help you scale your Xcode projects. ]]></summary>
      <link href="https://tuist.dev/blog/2018/07/28/introducing-tuist"/>
      <id>https://tuist.dev/blog/2018/07/28/introducing-tuist</id>
      <updated>Sat, 28 Jul 2018 00:00:00 +0000</updated>
      <content type="html"><![CDATA[ <p>
I started working on an Xcode project parser in Swift over a year ago. The goal was implementing a tool that would help large teams scale their Xcode projects. At that time I was doing much research on modularizing Xcode projects. It helped to overcome common issues such as compilation times, which <strong>had a very negative impact on developer&#39;s productivity and motivation</strong>. You can read more about it <a href="https://github.com/pepicrft/microfeatures-guidelines">here</a>.</p>
<p>
Modularization turned out to be an excellent step, but not enough. There was another set of challenges with which that Xcode and the existing tooling didn’t help. Complex Xcode projects, inconsistent settings that led to unexpected compilation errors, or non-standardized and unreliable automation DSLs are some examples of challenges that teams face when their organizations and projects grow.</p>
<p>
Companies like <a href="https://facebook.com">Facebook</a>, <a href="https://medium.com/airbnb-engineering/building-mixed-language-ios-project-with-buck-8a903b0e3e56">Airbnb</a>, <a href="https://eng.uber.com/ios-monorepo/">Uber</a>, or <a href="https://www.youtube.com/watch?v=wewAVF-DVhs">Pinterest</a> invest a fair amount of resources into addressing those challenges, for example, replacing the Xcode build system. However, not all the companies can afford it, and those have to battle the issues mentioned above on a daily basis. As you can imagine, that&#39;s one of the last things an app developer wants to be doing as part of their job.</p>
<p>
When I looked at the spectrum of tooling I found out that there were options on both extremes, but nothing in the middle for those medium-sized companies to adopt. One one side, there was Xcode, <code class="inline">xcodebuild</code>, and <a href="https://github.com/fastlane">Fastlane</a>, and on the other hand, alternative build systems such as <a href="https://github.com/facebook/buck">Buck</a>, or <a href="https://bazel.build">Bazel</a>.</p>
<p>
I felt there was a definite need for a tool, which had user-experience oriented focus, and that helped medium-size companies overcome the scaling struggles. I&#39;m happy to share with you a very early version of that tool, Tuist. In this blog post I&#39;ll talk about the goal of Tuist, how we plan to achieve it, and hopefully, convince you to give it a try and contribute to the project.</p>
<h2 id="🙉-what-makes-scaling-difficult?" tabindex="-1" class="marketing__blog_post__body__content__heading">
🙉 What makes scaling difficult?<a href="#🙉-what-makes-scaling-difficult?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 🙉 What makes scaling difficult?"></a></h2>
<p>
Before we dive into what Tuist does and how I think it&#39;s important to understand why Tuist in the first place. I briefly mentioned in the introduction that the growth of a project comes with some challenges which I&#39;d like to extend in this section. In my experience, the points below are a typical pattern in medium-size companies:</p>
<ul>
  <li>
    <p>
<strong>Configuring the project right:</strong> Configuring a multi-target project is cumbersome unless we use CocoaPods to define the project, which does all that work for us. As opposed to Android, where Gradle infers most of the build settings for you, Xcode expects us to do it right. That&#39;s not easy, especially if it&#39;s a large project with transitive dependencies. When we create a new project, it compiles and everything works, but as we start adding targets, dependencies, build settings, it&#39;s our responsibility to make sure the project configuration is in a healthy state. The validation of our settings usually happens at compilation time, and sometimes when we are sending the app to the store.    </p>
  </li>
  <li>
    <p>
<strong>Non-actionable errors</strong> When something unexpected happens, we may get an error that doesn&#39;t tell us much about what happened. <em>What caused this?</em> <em>What does this mean?</em> <em>What do I need to do to fix this?</em> Sometimes, the solution is reverting our changes on git and trying again.    </p>
  </li>
  <li>
    <p>
<strong>Non-standard DSLs:</strong> How do I build target <code class="inline">Core</code>? Should I execute <code class="inline">fastlane build_core</code>, or is it <code class="inline">fastlane core_build</code>? Fastlane is powerful, and gives us tons of flexibility, but that comes at a cost: inconsistencies and complexity. On one side, each project defines their set of lanes, which are maintained by the team responsible for the project. Unless the collaboration and communication is is good across teams, each <code class="inline">Fastfile</code> in the project will be different from the others, even though they usually expose a similar set of actions. Furthermore, those <code class="inline">Fastfiles</code> are rarely tested, which leads to unreliable automation logic that breaks at any time without us noticing it. Have you ever experienced your continuous integration pipelines green for a week, and then failing when you try to release the app to the store?    </p>
  </li>
  <li>
    <p>
<strong>Reusing configuration:</strong> In apps made of multiple projects or targets, it&#39;s common that those targets have a similar structure. While Xcode allows reusing build settings across them by using <code class="inline">.xcconfig</code> files, that&#39;s the only thing you can reuse. <em>What if we&#39;d like to have the same linking frameworks section because all the targets link the same dependencies?</em> <em>What if we&#39;d like to have similar schemes for those targets?</em> Well, that&#39;s not possible in Xcode projects. In my experience, those kinds of projects end up with a lot of duplicated information. <em>Why would we reuse code but not or projects configuration?</em>    </p>
  </li>
</ul>
<h2 id="🧠-how-does-it-work?" tabindex="-1" class="marketing__blog_post__body__content__heading">
🧠 How does it work?<a href="#🧠-how-does-it-work?" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 🧠 How does it work?"></a></h2>
<p>
<strong>In a nutshell, Tuist leverages projects generation to address those challenges.</strong> Instead of having Xcode projects and workspaces, developers define the projects in manifest files, which Tuist uses to generate the projects and workspaces and provide you with a reliable, easy to use and standard actions.</p>
<p>
A manifest file is a <code class="inline">Project.swift</code> file, which looks like this:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
swift    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="swift">
import ProjectDescription

let project = Project(
    name: &quot;MyApp&quot;,
    targets: [
        Target(
            name: &quot;MyApp&quot;,
            platform: .iOS,
            product: .app,
            bundleId: &quot;io.tuist.MyApp&quot;,
            infoPlist: &quot;Info.plist&quot;,
            sources: &quot;Sources/**&quot;,
            dependencies: [
                /* Target dependencies can be defined here */
                /* .framework(path: &quot;framework&quot;) */
            ]
        ),
        Target(
            name: &quot;MyAppTests&quot;,
            platform: .iOS,
            product: .unitTests,
            bundleId: &quot;io.tuist.MyAppTests&quot;,
            infoPlist: &quot;Tests.plist&quot;,
            sources: &quot;Tests/**&quot;,
            dependencies: [
                .target(name: &quot;MyApp&quot;)
            ]
        )
    ]
)    </shiki-highlight>
  </div>
</div>
<p>
If you have used the <a href="https://swift.org/package-manager/">Swift Package Manager</a> before, this approach might sound familiar to you. One of the benefits of defining the project in a Swift file instead of formats like YAML or JSON is that you can leverage Xcode to validate the syntax and get code auto-completion.</p>
<p>
Generating the project allows <strong>understanding your project</strong> and <strong>hiding implementation details and complexities</strong>. Some project elements are intentionally not available in the manifest. Instead, we provide a more straightforward interface, and we deal with the complexity.</p>
<p>
Take for instance linking dependencies. You might already know that all transitive dynamic dependencies need to be embedded into the apps. If you forget about any transitive dependencies, you end up the simulator linker complaining about frameworks not found. With Tuist, that&#39;s not a problem. You tell us what depends on what, and we set up the right build settings and build phases.</p>
<p>
Getting your input through manifest files allows, not only generating a valid project but providing a <strong>set of commands that reliably work with those projects</strong>. As opposed to Fastlane, where you should write lanes that take the right arguments, Tuist knows the structure of the project and can infer most of those things for you. The goal is that developers should be able to land on a folder, where there&#39;s a project defined, and interact with it, without having to guess which commands are available and which arguments need to be passed. Pretty much like:</p>
<div id="marketing-window">
  <div data-part="bar">
    <div data-part="language">
bash    </div>
    <div data-part="copy">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8C8.22614 8 8 8.22614 8 8.5V13.4993C8.0003 13.5876 8.02386 13.6742 8.06831 13.7505C8.11285 13.827 8.17677 13.8903 8.25363 13.9341C8.49353 14.0709 8.57713 14.3762 8.44037 14.6161C8.30361 14.856 7.99827 14.9396 7.75837 14.8029C7.52857 14.6719 7.33742 14.4825 7.20426 14.254C7.0711 14.0254 7.00064 13.7657 7 13.5012L7 13.5V8.5C7 7.67386 7.67386 7 8.5 7H13.5C13.7812 7 14.0315 7.07491 14.2452 7.23005C14.4481 7.37734 14.5847 7.57311 14.687 7.757C14.8212 7.99833 14.7343 8.30277 14.493 8.43698C14.2517 8.57118 13.9472 8.48434 13.813 8.243C13.7443 8.11939 13.6934 8.06516 13.6578 8.03932C13.633 8.02134 13.5938 8 13.5 8H8.5ZM10.8335 10C10.6124 10 10.4004 10.0878 10.2441 10.2441C10.0878 10.4004 10 10.6124 10 10.8335V15.1665C10 15.276 10.0216 15.3843 10.0634 15.4855C10.1053 15.5866 10.1667 15.6785 10.2441 15.7559C10.3215 15.8333 10.4134 15.8947 10.5145 15.9366C10.6157 15.9784 10.724 16 10.8335 16H15.1665C15.276 16 15.3843 15.9784 15.4855 15.9366C15.5866 15.8947 15.6785 15.8333 15.7559 15.7559C15.8333 15.6785 15.8947 15.5866 15.9366 15.4855C15.9784 15.3843 16 15.276 16 15.1665V10.8335C16 10.724 15.9784 10.6157 15.9366 10.5145C15.8947 10.4134 15.8333 10.3215 15.7559 10.2441C15.6785 10.1667 15.5866 10.1053 15.4855 10.0634C15.3843 10.0216 15.276 10 15.1665 10H10.8335ZM9.53702 9.53702C9.88087 9.19317 10.3472 9 10.8335 9H15.1665C15.4073 9 15.6457 9.04743 15.8681 9.13957C16.0906 9.23171 16.2927 9.36676 16.463 9.53702C16.6332 9.70727 16.7683 9.9094 16.8604 10.1319C16.9526 10.3543 17 10.5927 17 10.8335V15.1665C17 15.4073 16.9526 15.6457 16.8604 15.8681C16.7683 16.0906 16.6332 16.2927 16.463 16.463C16.2927 16.6332 16.0906 16.7683 15.8681 16.8604C15.6457 16.9526 15.4073 17 15.1665 17H10.8335C10.5927 17 10.3543 16.9526 10.1319 16.8604C9.9094 16.7683 9.70727 16.6332 9.53702 16.463C9.36676 16.2927 9.23171 16.0906 9.13957 15.8681C9.04743 15.6457 9 15.4073 9 15.1665V10.8335C9 10.3472 9.19317 9.88087 9.53702 9.53702Z" fill="#171A1C">
        </path>
      </svg>
    </div>
  </div>
  <div data-part="code">
    <shiki-highlight language="bash">
tuist generate
tuist build
tuist test
tuist run    </shiki-highlight>
  </div>
</div>
<p>
If the arguments can be inferred, they will be inferred. If an input is invalid, we&#39;ll fail early instead of delegating that to the build system. Tuist is designed to fail soon and clearly. We want you to know when things go wrong, why so, and what you can do about them.</p>
<p>
<strong>Xcode is a great tool, and we&#39;d love you to continue to use it, but without the hassle of having to maintain a project and all the automation around it.</strong></p>
<h2 id="🖌-design-principles" tabindex="-1" class="marketing__blog_post__body__content__heading">
🖌 Design principles<a href="#🖌-design-principles" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 🖌 Design principles"></a></h2>
<p>
I read that GitHub came up with <a href="https://ben.balter.com/2015/08/12/the-zen-of-github/">some design principles</a> which they shared across all the teams to make sure that they were all aligned when building features for the platform. I liked the idea and drafted a list for Tuist. This is what I came up with:</p>
<ul>
  <li>
    <p>
<strong>Convention over configuration:</strong> Build things to be convenient, not configurable. Configurability gives users the power to use the tool as they want, but also to screw things up without you being able to recover from it.    </p>
  </li>
  <li>
    <p>
<strong>Design for failure:</strong> Quoting Murphy: <em>&quot;If things can go wrong, they will&quot;</em>. Don&#39;t assume the happy path is the only valid path. Any scenario is handled, including errors, letting developers know about it at any time.    </p>
  </li>
  <li>
    <p>
<strong>Make feedback actionable:</strong> If things go wrong try to recover from it. In case you can&#39;t, let developers know what to do to get it working. There&#39;s a significant difference between <code class="inline">Couldn&#39;t find the simulator</code>, and <code class="inline">Couldn&#39;t find the simulator because simctl was not found in the system. Make sure the Xcode installation is configured by running &#39;xcode-select -p&#39;</code>    </p>
  </li>
  <li>
    <p>
<strong>Simple is better than complex:</strong> People don&#39;t use things if they are too complex. Developers don&#39;t want to touch a piece of code that has grown into a huge mess. Keep things simple.    </p>
  </li>
  <li>
    <p>
<strong>Implementation details bring little value to users:</strong> Users don&#39;t want to know how you are doing things internally, they want you to do what they asked you for. Don&#39;t expose implementation details, like errors that you are thrown internally, because they don&#39;t care about that.    </p>
  </li>
  <li>
    <p>
<strong>If it can&#39;t be reliable, you&#39;d better not build it:</strong> If a feature doesn&#39;t work as expected, users will have a negative perception of the tool. If you plan to build something, which can&#39;t be reliable, don&#39;t build it. Instead, do some groundwork to make it reliable or find another approach to address the same problem.    </p>
  </li>
</ul>
<p>
It&#39;s is a malleable list which will change and grow as the project evolves. You can check out the <a href="https://github.com/tuist/contributors/blob/main/Zen.md">full list</a> on the <a href="https://github.com/tuist/contributors">contributors&#39; repository</a></p>
<blockquote>
  <p>
We implemented an endpoint, <a href="http://api.tuist.io/zen">api.tuist.io/zen</a>, to return the project design principles.  </p>
</blockquote>
<h2 id="🚀-what's-coming" tabindex="-1" class="marketing__blog_post__body__content__heading">
🚀 What&#39;s coming<a href="#🚀-what's-coming" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 🚀 What's coming"></a></h2>
<ul>
  <li>
📃 <strong>Documentation:</strong> Unfortunately, We haven&#39;t devoted much time to have a decent documentation for the project. That makes onboarding hard. We&#39;ll work on documenting the public interfaces and the CLI.  </li>
  <li>
🚀 <strong>Build, test, run actions:</strong> We&#39;ll work on providing a standard interface with the most common actions developers do when they interact with the projects. Once developers learn the interface, they&#39;ll be able to jump from one project to another seamlessly.  </li>
  <li>
🔀 <strong>Static transitive dependencies:</strong> Although Tuist supports dynamic transitive dependencies, it doesn&#39;t support static ones. We want to add support for that, allowing developers to specify whether they&#39;d like to generate their dependencies to be static or dynamic.  </li>
  <li>
🔑 <strong>Certificate management:</strong> A common source of frustration when building apps with Xcode is when you try to run the app on a device, or archive it for release, and you get a signing issue. We want to address that by setting up the environment and project with the right certificates, provisioning profiles and build settings.  </li>
  <li>
🛒 <strong>Releasing:</strong> Once the app is ready for release, we&#39;d like you to be able to archive and send the app to the store directly from Tuist with a single command that does all the heavy-lifting for you.  </li>
</ul>
<p>
You can check out <a href="https://github.com/tuist/tuist/issues">the project issues</a> that contains some other smaller improvements and features that are also coming to the project.</p>
<h2 id="📱-start-using-it" tabindex="-1" class="marketing__blog_post__body__content__heading">
📱 Start using it<a href="#📱-start-using-it" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 📱 Start using it"></a></h2>
<p>
Would you like to give Tuist a try? You can check out the <a href="https://docs.old.tuist.io/tutorial/get-started/">Get started</a> guide that explains how to install the tool and how to bootstrap your first project.</p>
<h2 id="📒-resources" tabindex="-1" class="marketing__blog_post__body__content__heading">
📒 Resources<a href="#📒-resources" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to 📒 Resources"></a></h2>
<ul>
  <li>
<a href="https://tuist.io/vision/">The vision of the project</a>  </li>
  <li>
<a href="https://github.com/tuist/contributors/blob/main/Zen.md">Design principles</a>  </li>
  <li>
<a href="https://github.com/tuist/contributors/blob/main/Contributing.md">Contributing</a>  </li>
</ul>
<h2 id="❤️-i-need-you" tabindex="-1" class="marketing__blog_post__body__content__heading">
❤️ I need you<a href="#❤️-i-need-you" class="marketing__blog_post__body__content__heading__anchor" aria-label="Permalink to ❤️ I need you"></a></h2>
<p>
Tuist strives to build a healthy and supportive community that pushes the project forward. I&#39;ll keep pushing it because I&#39;m self-motivated, but I&#39;d love to do it with developers like you.</p>
<p>
<strong>We need feedback, ideas, bugs, code, and whatever you can imagine to make Tuist better</strong>. I&#39;ve built the project to be accessible and inclusive to make sure everyone has a voice and can participate in shaping Tuist. I planted the seed, but this tree 🌲 needs passionate gardeners.</p>
<p>
Don&#39;t be afraid of getting involved with the project. If you have never done it before, <a href="mailto:pedro@ppinera.es">drop me a line</a>, and I&#39;ll be pleased to get you onboard. If you are a developer for Apple platforms, you&#39;ll feel like at home working on this project because it&#39;s written in plain Swift, a programming language you might already be familiar with.</p>
<br>
&lt;br/&gt;<p>
I&#39;m thrilled about this project taking off; nevertheless, there&#39;s a possibility of this project not being used a lot since there&#39;s already trust in the community for Fastlane, Cocoapods, or the official Swift Package Manager. I&#39;ll do my best though, but without worrying too much. Overall, I&#39;d like to learn how to build a user-friendly and reliable command line tool that addresses real problems developers have.</p>
<p>
Having said all that, I can&#39;t wait to see how you use Tuist and all the ideas that come out of it.</p>
<p>
Happy Xcoding! ❤️👩‍💻</p>
 ]]></content>
    </entry>
  
</feed>
