Skip to main content
Tutorials

AI iOS app development in VS Code with Copilot and Claude Code

An AI coding assistant can write Swift code for you, but that code only counts once it compiles, installs on a phone and runs. In this tutorial KXBuild handles code completion, building and on-device debugging, while an AI assistant such as GitHub Copilot or Claude Code writes and edits the code. You add a small feature to a to-do app on Windows and go through the whole loop of describing the change, reviewing the code, building, testing on your iPhone and fixing bugs.

The example continues with MyTodo, the to-do list app from your first SwiftUI app. If you don’t have that project, any iOS project that builds with KXBuild works the same way.

Prepare

Start with the KXBuild side. Install KXBuild and the VS Code extension by following the install page, open the project folder with File > Open Folder…, and press F5 once to confirm the app installs and runs on your phone.

Then make sure code completion works. Open a Swift file and type Text("a").. A list of modifiers should pop up, and mistakes get a red underline. If completion doesn’t appear, run KXBuild: Restart Code Completion from the Command Palette. For other cases see Code completion and indexing. With code completion working, problems in code the AI changed are marked in the editor right away, before you build.

Install and sign in to the AI assistant by following its official docs, for example GitHub Copilot or Claude Code. You use them in an iOS project the same way as in any other project.

Give the AI project context

By default the AI doesn’t know this is an iOS project, which iOS version it targets or which dependencies it can use. It may write APIs your deployment target doesn’t support or pull in third-party libraries the project doesn’t have. Put an instructions file in the repository, and the AI reads it at the start of every conversation.

Each tool reads a different file. The common ones are below. Check each tool’s docs for the exact format.

Tool Instructions file
GitHub Copilot .github/copilot-instructions.md
Claude Code CLAUDE.md in the repository root
Cursor Rule files in the .cursor/rules folder

Write down facts the AI can’t work out by itself but that affect the code. To find the minimum iOS version, right-click the target in the KXBuild view, choose KXBuild: Edit Target Settings and look at the General page. Here is the file for MyTodo.

1# MyTodo
2
3- iOS app, SwiftUI, Swift 5, minimum iOS 15.0. Don't use APIs that require iOS 16 or later (such as @Observable, SwiftData, NavigationStack). If you really need one, wrap it in if #available.
4- No third-party dependencies. Don't add new Swift packages or CocoaPods.
5- Code is in the MyTodo/ folder. ContentView.swift contains TodoItem (data), TodoStore (reads and writes Documents/todos.json) and ContentView (UI).
6- TodoItem is already stored on users' phones. New fields must be optional or have a default value so old data can still be read.
7- After changing code, run kxbuild build .\MyTodo.xcodeproj -D CODE_SIGNING_ALLOWED=NO in the project folder to check that it compiles. If there are errors, keep fixing until it passes.
8- Don't read or modify the keychain/ folder.

The last two lines let the AI check the build by itself without touching your certificates. The sections below rely on them.

Build a small feature

Add due dates to to-dos and a way to sort by due date. The feature is small, but it touches the data, the UI and the existing storage, which makes it a good test of AI-written code.

Write the prompt

Spell out what you want, where it goes and what must not change. The more specific you are, the closer the generated code gets to what you want.

1Add due dates to to-dos with these requirements.
21. Add an optional due date to TodoItem.
32. Add a toggle to the add area. When it's on, show a date picker, and include the date when adding.
43. In each row, show the date in small text under the title. Show it in red if the to-do isn't done and the date is before today.
54. Add a "Sort by date" button on the left of the navigation bar. To-dos with a date come first, earliest to latest, followed by those without a date.
6Don't change how TodoStore stores data.

Review the generated code

When the AI is done, look at what it changed before you decide to keep it. The Source Control view in VS Code shows the diff file by file. Below are the key parts of one acceptable version.

1struct TodoItem: Identifiable, Codable {
2    var id = UUID()
3    var title: String
4    var done = false
5    var dueDate: Date?
6}
1Toggle("Due date", isOn: $hasDueDate)
2if hasDueDate {
3    DatePicker("Date", selection: $newDueDate, displayedComponents: .date)
4}
1if let due = item.dueDate {
2    Text(due, style: .date)
3        .font(.caption)
4        .foregroundColor(isOverdue(item) ? .red : .secondary)
5}
 1private func isOverdue(_ item: TodoItem) -> Bool {
 2    guard let due = item.dueDate, !item.done else { return false }
 3    return due < Calendar.current.startOfDay(for: Date())
 4}
 5
 6private func sortByDueDate() {
 7    store.items.sort { a, b in
 8        switch (a.dueDate, b.dueDate) {
 9        case let (x?, y?): return x < y
10        case (_?, nil): return true
11        default: return false
12        }
13    }
14}

Focus on these points when reviewing.

  • Data compatibility. dueDate is optional, so the todos.json already on the phone still loads without that field. With a non-optional field such as var dueDate: Date, decoding old data fails and the user’s to-dos are wiped.
  • How it sorts. This version sorts store.items in place, so the sorted result gets saved, and checking off and swipe-to-delete keep working. Some versions add a separate sorted computed property for ForEach. The bindings and onDelete indexes then don’t match the original array, and the wrong row gets deleted.
  • API availability. Text(_:style:) and DatePicker are both available on iOS 15. If you see newer APIs such as NavigationStack or @Observable, ask the AI to change them back according to the instructions file.
  • Scope of changes. Only what needed to change was touched, with no unrequested rewrites of other code and no new dependencies.

Build and test on your iPhone

Press F5. KXBuild builds, signs, installs and launches the app. Compiler errors appear in the Problems panel. Click one to jump to the line.

On the phone, try these in order. Add two to-dos with different dates and one without a date, then tap “Sort by date” and check the order. Set one date to yesterday, confirm it shows in red, and check it off to see it turn gray again. Swipe the app away in the app switcher, open it again, and confirm the dates and order are still there.

Set a breakpoint in sortByDueDate(). When it pauses after you tap the sort button, type po store.items in the Debug Console to see the data before sorting. For breakpoints and variables see Run and debug.

Let the AI fix errors

How well the AI fixes a bug depends on what you give it. “It doesn’t work” is hard to act on. Give it the full error text, the steps that trigger the problem and the relevant code.

Build errors

When the build fails after F5, the full log is in Output > KXBuild and the errors are in the Problems panel. Copy the error lines, including file names and line numbers, to the AI. A complete compiler error looks like this.

1MyTodo\ContentView.swift:21:29: error: cannot convert value of type 'String' to expected argument type 'Int'

When one error causes a cascade of others, give only the first one. The rest usually go away with it.

Runtime issues

When the app launches but behaves wrong, first ask the AI to add print calls in the suspect places, press F5 again to reproduce, and paste the output from Output > KXBuild Console back to it. You can also set breakpoints yourself and tell it the variable values you see in the Debug Console.

Crash reports

When the app crashes, download the crash reports from the phone.

1kxdevice crash list MyTodo*
2kxdevice crash pull .\crashes MyTodo*

When you give a report to the AI, tell it what you did before the crash. The exception type, the Last Exception Backtrace and the crashed thread’s call stack in the downloaded .ips file are what the AI mainly uses to find the problem. If the call stack has no function names, reproduce the crash with F5 in the Debug configuration. The debugger stops on the line that crashed, and giving the AI that line and the call stack is more direct. For how to read reports see on-device debugging.

Let the AI run the build

AI assistants that can run terminal commands, such as Copilot and Claude Code, can run kxbuild build themselves, read the errors and keep editing until the build passes. The instructions file already contains the command, and you can also ask for it directly in the prompt, for example “build after your changes and fix any errors”.

1kxbuild build .\MyTodo.xcodeproj -D CODE_SIGNING_ALLOWED=NO

-D CODE_SIGNING_ALLOWED=NO only checks that the code compiles and skips signing, so the AI never needs your certificates. When the build fails, the command exits with a non-zero code and prints errors as file:line:column: error: message, which the AI can read and map to the code directly. If your project is a .xcworkspace, use it in place of the project file in the command. For the options see Build and configuration.

This division of work is convenient. The AI handles the edit, build, read errors, edit again loop. Once the build passes, you review the changes and press F5 to check the UI and interaction on your phone. A passing build doesn’t mean the feature is correct, so don’t skip testing on the device.

Things to watch

  • Review every change. The AI may change things you didn’t ask for, or write code that compiles but has wrong logic. Commit in small steps so it’s easy to roll back.
  • Check the deployment target. The AI generates the patterns it has seen most, which may not suit your minimum iOS version. When the build reports errors like is only available in iOS 16.0 or newer, ask it to use an older API or add if #available.
  • Add usage descriptions. When the AI adds features that use the camera, photo library, location or microphone, add the matching usage description to Info.plist, such as NSCameraUsageDescription. Without it the app crashes when it accesses the feature, and App Review rejects it. For projects with a generated Info.plist, see app icon, launch screen and localization.
  • Keep certificates and passwords out of the AI’s context. Don’t paste the .p12 files or password.properties in the keychain folder to the AI, and don’t let it read them. Every AI tool has an ignore file or exclude setting, so exclude this folder. The same goes for your Apple Account password and App Store Connect API keys.
  • Test it yourself before committing. Tap through the new feature and any affected existing features on the phone. For data changes, also check that old data still works after installing over the previous version.