scriptable.com

Implementation-focused, hands-on tutorials for software engineers.

To get the source, just point your LLM at an article and ask it to build it.

Version, Archive and Tag Each App in a Swift Monorepo

The monorepo from A Swift Monorepo with an Xcode Workspace and Local Packages builds two iOS apps from shared packages, but it cannot release them one at a time. Both apps report version 1.0, build 1. Their version numbers are typed into each project’s target settings, where a release would have to edit them in Xcode. Shopping has no display name of its own, neither app has an icon, and make archive keeps no record of what it shipped or when. ...

29 min

A Swift Monorepo with an Xcode Workspace and Local Packages

The to-do app from the earlier articles in this series lives in one Xcode project with one package beside it. A second app that needs the same code has two poor options: copy the files, or point a second project at a folder inside the first. A monorepo, one repository holding several apps and the code they share, avoids both, and an Xcode workspace ties it together: it lists projects and packages, opens them in one window, and builds them as one. ...

32 min

The Xcode Build Process from the Command Line, with make

Pressing Run in Xcode hides a chain of decisions: which scheme to use, which targets to build and in what order, which build configuration, which device, where the output goes, and which of several hundred build settings apply. When a build behaves differently in Xcode than on the command line, or a setting you changed seems to do nothing, the cause is almost always one of those hidden choices. This article makes each one visible with xcodebuild, the command-line tool behind Xcode’s Run button, using the todo-list folder from Build a Swift Package with Swift Package Manager on macOS. You will read the project’s schemes, targets, configurations and destinations from the terminal; find where each build lands; see which build settings apply and where each value came from; and put your own settings in .xcconfig files, plain-text files of build settings that Xcode layers under the project’s own. Those files give Debug builds the name To-Do Dev on the simulator’s home screen and Release builds the name To-Do, so you can tell at a glance which configuration you are running. The Makefile grows a CONFIG switch, a settings make target that prints the settings that matter, and an archive make target that produces the Release build you would later sign and upload. Every later article in this series uses this Makefile. ...

20 min

Build a Swift Package with Swift Package Manager on macOS

The to-do app from Build Your First SwiftUI App on macOS keeps its model inside the app target. That works for one app, but nothing else can use the code, and its unit tests can only run by building the whole app and booting an iPhone simulator. This article moves that model into a Swift package: a folder of Swift code described by a Package.swift file, which Swift Package Manager (SwiftPM, the build tool that ships with Swift) can build and test on its own. You will create a library package named TodoKit, move the TodoItem model and its five unit tests into it, and run those tests on your Mac with swift test in about a second, with no simulator. Then you will add the package to the Xcode project as a local dependency, so the app imports TodoKit instead of owning the model. The finished project runs the package tests and the UI test from one make test, and the app still shows the to-do you saved in the first article, read from the same database by code that now lives in the package. ...

22 min

Build Your First SwiftUI App on macOS

Many first SwiftUI tutorials stop once the app appears in Xcode’s preview canvas. That leaves out the parts you need before an app is real: data that survives a relaunch, tests that prove it, and a way to build and run the whole thing without clicking through the IDE. This article builds a to-do list app for iPhone with SwiftUI, Apple’s declarative UI framework, and SwiftData, Apple’s framework for saving Swift objects to an on-device database. The result is an Xcode project that you build, test, and launch in the iOS Simulator with three make commands. Its test suite includes a UI test that adds a to-do, quits the app, relaunches it, and checks the to-do is still there. You will run that test, then open the app and see the saved item yourself. ...

34 min

Query Parquet, CSV, and JSON Files with DuckDB and Python on macOS

Data rarely arrives in one format. Customer records come out of a spreadsheet as CSV, an analytics pipeline drops order history as Parquet, a compact binary format for tables, and the app logs events as JSON, one object per line. The usual Python answer is to load each file into pandas, fix up the types, and merge the frames by hand. DuckDB lets you skip the loading: you write SQL against the files themselves, and a single query can join a CSV to a Parquet file to a JSON log. ...

28 min

Red-Team an Open-Weight LLM on Your Mac with NVIDIA garak and Ollama

This tutorial ends with NVIDIA’s garak scanner attacking an open-weight model running on your own Mac, and with you able to answer a question most teams answer by guesswork: did this change to my prompt make the model easier or harder to hijack? You will scan Llama 3.2 3B (3 billion parameters), served locally by Ollama, with hundreds of prompt-injection attacks, read the individual attacks that worked, then write two defensive system prompts and measure each one against the same attacks. The first one makes the model more vulnerable. The second helps against one kind of injection and is indistinguishable from noise against the other. You will finish with a make gate target that fails a build when a prompt change pushes the attack success rate past a threshold you choose. Nothing leaves the machine: no API keys, no hosted model, no account. ...

38 min

Getting Started with Apache Kafka on macOS: Run a Broker and Stream Events with Python

This tutorial ends with an Apache Kafka broker running in Docker on your Mac, a topic named orders, and two Python programs that talk to it: a producer that publishes JSON order events and a consumer that reads them. You will then use those programs to show the property that makes Kafka different from a job queue. Reading a message does not remove it, so a consumer that restarts picks up where it stopped, and a second, independent consumer can replay the whole history from the beginning. You will see both happen, and measure how far behind a consumer is, with Kafka’s own tools. ...

26 min

Run Laya Locally on Apple Silicon and Measure Its Confidence Yourself

Laya is an open-weights model from Convai Innovations that answers typed questions about a piece of text instead of writing prose. You hand it a state (a support thread, an email, a JSON record) and a set of questions, each of which declares the shape of its answer in advance: pick one option from a list, place the text on an ordered scale, or give the probability that a statement is true. Every answer comes back as a probability distribution over the options you declared. Laya is an encoder, a network that reads text and scores it rather than writing any. Each call is one forward pass (a single run of the network over the input), with no generated text to parse. ...

41 min

Fine-Tune a Local Model with LoRA on Apple Silicon using MLX

By the end of this article you will have trained a language model to do something it currently cannot do, on your own Mac, in about twenty seconds of compute. You will hand it a bug report in plain English and it will answer with exactly one line: severity=high component=auth summary=login fails after the token refresh runs The base model does not do this. Asked the same question it starts explaining token refresh and never reaches a parseable answer. You will measure that difference rather than eyeball it: twenty test reports held out of training so the model has never seen them, which the base model scores 0/20 on and your fine-tuned model scores 20/20 on, run by a script you write in Step 8. ...

40 min