Issue #157

When Build in Public Goes Back Underground

Cover for Weekly Issue 157

Over the past few months, the community has seen a growing number of cases where AI is used to quickly reverse-engineer commercial products or create pixel-perfect replicas of popular apps. With enough tokens to burn, building a free “shadow version” no longer seems particularly difficult.

At the same time, many indie developers who embrace Build in Public are facing a new challenge: while the original product is still being refined, imitators can take the screenshots and ideas its creator has shared on social media, feed them to AI, and launch a clone before the original is even ready. Some do it out of technical curiosity and experimentation; others simply want to showcase what AI tools can produce. But there are also those who see it as an easy shortcut.

Watching this trend unfold, I can’t help feeling a little uneasy.

Cloning and imitation have existed for decades, but AI has dramatically reduced the time and cost required for implementation. An original creator may spend months discovering an idea worth pursuing, while an imitator can look at the finished result, skip much of the trial and error, and produce something remarkably similar in appearance and functionality in a very short time.

Competition, of course, needs challengers, and AI can be just as helpful to original creators. If lower implementation costs push teams to innovate faster, improve the experience, or offer better value, that is something consumers should welcome. After all, copying an interface or a feature set is not the same as copying the product itself. The design judgments hidden in the details and the deep understanding of users’ needs cannot be reproduced through a pixel-perfect clone alone.

But not every creator has enough time and resources to wait for the market to recognize those differences. For an established commercial product, a few AI-generated clones may not pose much of a threat. For an indie developer still trying to find a place in the market, however, a lead of just a few weeks or months can matter enormously.

Build in Public used to be a way for indie developers to build a community and gather feedback by sharing their ideas, designs, and development process. More importantly, it encouraged people to share ideas, experiments, and even failures with other developers while their products were still rough and unfinished.

That kind of culture didn’t just appear out of nowhere. It was built gradually over the years.

But when publicly shared information also becomes a shortcut for others to find targets to clone and bypass the exploration process, the risks of sharing begin to change. If more developers conclude that staying quiet until a product is ready is safer than sharing openly, Build in Public may genuinely start turning back into Build in Private.

That is what makes me most uneasy.

What we stand to lose may not just be a few original products that never make it to market, but the hard-won culture among indie developers of sharing unfinished ideas with one another—and inspiring each other in the process.

Original

AI-Friendly Frameworks: As Abstraction Moves Up, How Can Verification Keep Pace?

With the rise of AI Coding, a growing number of people have begun to favor the idea that imperative frameworks like UIKit may be better suited to Coding Agents than SwiftUI. The reasoning is intuitive—UIKit’s logic is direct and explicit: create objects, set properties, add them to the hierarchy, establish constraints. Every step operates on something concrete. SwiftUI, by contrast, folds a great deal of implementation detail behind declarative syntax, where state, environment, identity, layout, and rendering together determine the final result. Once the rendered result deviates from expectations, an Agent is left facing a black box, trying to infer what happened internally from limited external observations.

But perhaps the problem is not abstraction itself. Rather, as abstraction moves up, we have neglected the other half of the work: observation and verification. When abstraction hides lower-level details, we need mechanisms at the new level that can make intent explicit and verify that it has been preserved.

Recent Recommendations

Revisiting “Split Isolation”

In a non-Sendable type with no actor isolation of its own, adding @MainActor to only some methods gives the same instance different isolation requirements. Matt Massicotte calls this pattern “split isolation.” Many developers, including Matt himself, have considered it a poor design.

In this article, Matt revisits his earlier assessment: while split isolation should still generally be avoided, it can have value in certain situations. In particular, when only a small amount of independent functionality depends on MainActor, or when migrating to Swift 6 and trying to prevent isolation requirements from rapidly spreading through a large existing codebase, adding @MainActor locally can be a reasonable or even necessary trade-off. Whether to use split isolation depends on whether it is obscuring the type’s true isolation requirements or deliberately expressing a localized constraint.


The Task Is Not the Unit of Work: Ownership, Isolation, and Cancellation Beyond async/await

SwiftUI’s .task automatically cancels a task when the view disappears. That’s convenient, but it can also make it all too easy for developers to tie the lifetimes of various business operations to the UI lifecycle. A disappearing screen, however, does not necessarily mean that the user’s intent has become irrelevant.

⁠Bruno Valente Pimentel points out that a Task is a unit of execution, but not necessarily a unit of product work; an Actor solves isolation, but does not decide who should own the work; structured concurrency can propagate cancellation, but cannot determine whether that parent-child relationship matches the product’s semantics. Rather than first asking “Where should I put my Task?”, Bruno suggests first defining the operation’s intent, owner, resource, and lifetime, and only then choosing the appropriate implementation mechanism. The compiler can help us ensure concurrency safety, but it cannot decide for us when a piece of work truly “stops mattering.”


A SwiftUI calendar with custom days and event indicators

When implementing a calendar UI, drawing the date grid is often not the difficult part. The real challenges lie in the state and edge cases behind it: separating the currently displayed date from the selected range; consistently using Calendar for date arithmetic and day boundaries; correctly handling the first weekday, month boundaries, daylight saving time, and non-Gregorian calendars; making taps and drags work together for continuous range selection; avoiding repeated scans of the event list in every cell; and preventing unnecessary cell view reconstruction. Szymon Lorenz shares what he learned while developing the calendar component for ⁠SwiftUIComponents, an open-source project that also provides Android compatibility through ⁠Skip Fuse.


SwiftUI Profiling with Instruments: 100,000 Calendar Events

When a SwiftUI app with a large dataset starts to stutter, is the problem in the database, data processing, or view updates? Maciej Szamowski stress-tested hora Calendar with a database containing 100,000 events. Using Instruments’ SwiftUI, Hangs, Hitches, and Time Profiler tools, he found that a large amount of main-thread time during stalls was being spent on SwiftUI graph updates, shifting the optimization focus away from the database and toward data preparation and the view update path.

Both of these calendar articles adopt similar optimization principles for improving rendering performance: avoid making individual cells perform repetitive work that can be handled at a higher level. Prepare data and interaction context upstream → let downstream Views receive values that are as stable and as close to their final presentation form as possible → keep information unrelated to rendering out of the SwiftUI observation/update graph.


Why your fastlane snapshot screenshots are all in English(and how to check every language)

When using fastlane snapshot to generate localized App Store screenshots in bulk, you may encounter a frustrating problem: the language directories are all created correctly, yet every screenshot still appears in English. What makes the issue particularly troublesome is that there is no single cause, making it difficult to diagnose.

Manuel Lorenzo Parejo⁠ lists five areas to investigate: when setupSnapshot is called; how snapshot is launched; localize_simulator; whether the App Bundle contains the corresponding .lproj; and whether residual app state is affecting the language setting. He also provides the free shotfleet check command, which recognizes text in screenshots and compares it against the app’s own localized strings, allowing you to verify in bulk whether the generated screenshots actually use the expected language.

Tools

Redlamp: A Native RAW Editor Built by a Photography Enthusiast with AI

Redlamp is an open-source macOS RAW photo editor built with Swift and Metal under the MPL-2.0 license, with a development-panel workflow familiar to Lightroom users. Its creator, Pedro Gomes, is both an engineer and a photography enthusiast who has ⁠long wanted more tools that fit the way he prefers to work.

Even though AI has played a significant role in developing the project, Redlamp still reflects clear personal intent and judgment. Pedro chose to make the photo library database a rebuildable index while keeping important information alongside the photos themselves. When measurements showed that an optimization around mask edges was sacrificing detail, he narrowed the scope where the algorithm would be applied. Decisions like these give Redlamp a distinct authorial imprint.

The project’s blog documents many of the ideas and trade-offs that emerged during development, while the repository also makes its collaboration rules and verification mechanisms for coding agents public. Pedro is exploring how multiple agents can participate in the continuous development of complex native software—and how to determine whether the results they deliver are actually reliable.


AnnotateIt: Closing the Loop from Annotation to Create ML Training on Mac

For developers who want to train custom Object Detection models with Create ML, the training itself is often not the most troublesome part. Data preparation is where much of the time goes: the Create ML app itself does not provide annotation tools, so developers typically need another tool to draw bounding boxes and then organize the results into a data format Create ML can use.

AnnotateIt brings these steps together in a single Mac app. After annotating images, you can train an Object Detector locally using Apple Create ML. The resulting model can then be applied to new images and videos to generate suggested annotations, which can be reviewed and corrected manually. For Swift developers, this not only lowers the barrier to experimenting with local Object Detection, but also connects “annotation → training → prediction → correction” into a complete workflow.

In the official parking-lot example, a model trained on 292 images completes in under a minute. The entire process requires neither a Python environment nor a cloud GPU, and the data can remain entirely on the local machine.


InnoDI: Turning the Dependency Graph into a Verifiable Build Artifact

InnoDI, developed by ⁠Ethan Parker, is a dependency injection framework built around Swift Macros. It turns the initialization and parameter-passing logic that would otherwise be written manually in an object graph into explicit dependency declarations, while generating container initializers and type-safe test override interfaces. Macros handle local diagnostics, an SPM Build Plugin validates the dependency graph across files and modules, and a companion CLI can inspect and analyze that graph.

InnoSquad’s InnoFlow, InnoRouter, and InnoNetwork follow a similar philosophy, reducing implicit behavior through explicit boundaries and repeatable verification: declare constraints up front wherever possible, and leave runtime behavior to unified execution policies.

In the age of AI Coding, framework authors need to rethink who their consumers are. “Making code easier for developers to write” may no longer be the only top priority. When the cost of learning is no longer borne entirely by human developers, “making the intent and behavior of code easier to verify” is rapidly becoming more important.


SimAgentation: Annotate the iOS Simulator in Your Browser and Hand the Work to AI

When using AI to adjust an interface, accurately expressing “this is what needs to change” can often take more effort than describing the change itself. SimAgentation, developed by citron, lets developers interact with the iOS Simulator from a browser (IOSurface -> VideoToolbox -> WebCodecs), select UI elements or draw a box around a region, and write modification requests directly. The tool sends the feedback, along with element information, source-code search hints, full-screen screenshots, and cropped screenshots, to a coding assistant through MCP, while displaying the processing status in the browser.

The optional SimAgentationPlus adds .simTag() for attaching names, files, and line numbers to views. This shares some similarities with the element-anchor approach I used in FlowCanvas: combining visual output with structured information so that AI can understand the target of feedback more precisely.

Related Weekly

Subscribe to Fatbobman

Weekly Swift & SwiftUI highlights. Join developers.

Subscribe Now