VIA Terminal spent a year in Processing
I shelved my iOS terminal app in 2025 because I thought compiler warnings were blocking the App Store. A year later Fable 5 fixed all 74 of them in ten minutes, and the real blockers turned out to be a broken plist, stale CPU slices and a framework the app never used.
Two builds of VIA Terminal in my App Store Connect account have said "Processing" since September 2025. Version 1.0, builds 1 and 3. They never finished and they never failed. Apple's API doesn't return them, so nothing can delete them. They sit at the bottom of the TestFlight page like fossils.
Those two uploads are the whole record of my first attempt to ship the app.
A week in August
VIA Terminal started as the phone side of VIGIL, the Raspberry Pi camera system I wrote about here before. It's an SSH client with camera monitoring built in, wrapped in a Windows 95 shell with a pixel-art Roman forum on the splash screen.
The git log covers it in four commits. Initial commit on August 26, 2025. "ssh working" on the 27th. "pretty good state working on cameras" on the 28th. "everything working" on September 1. By then it had a terminal built on SwiftTerm, camera feeds tunneled over SSH, a home screen widget, Live Activities and an iMessage sticker pack of Roman imperial art.
Then I tried to upload it.
The wall
Xcode showed about eighty warnings. The uploads went into Processing and stayed there. I connected those two facts, decided the warnings were the blocker, and looked at a pile of Swift concurrency complaints in SSH and camera code I had written in a hurry. I had a working app on my own phone. I shelved it.
I had the cause wrong. Xcode warnings don't block an upload. It took me a year to find that out.
Back in it
On August 2, 2026 I opened Claude Code and typed, close to verbatim, "now that you are Fable 5 I think we can chug through and fix all of those." First I asked it to find the repo, because I didn't remember where the code lived. Fable 5 searched GitHub code for terminalis, the domain in the bundle ID, and found the app in a subfolder of my vigil-ios repo. I had never given it a repo of its own.
Getting it to compile again took the first few hours, and none of that was code. Xcode 26 ships without the iOS platform, so that was an 8.4 GB download. SwiftTerm compiles Metal shaders, and the Metal toolchain is a separate download now too. CocoaPods needed reinstalling for VLCKit. Four gitignored frameworks had to come back from the ios_system v3.0.5 release. Each missing piece failed the build with a different error, one at a time.
When it finally built, the count was zero errors and about eighty warnings.
Ten minutes
Fable 5 split the warnings into three groups that shared no files (concurrency, deprecations and everything else) and gave each group to its own agent. They ran in parallel. About ten minutes later all 74 warnings in my own code were gone.
The concurrency agent did the part I had been dreading, and it didn't suppress anything to get there. The SSH channel handler now goes in through NIO's synchronous pipeline operations inside the channel initializer, which already runs on the event loop. A racy flag in the network scanner became a real lock. The one @unchecked Sendable it left behind came with a TODO explaining why a lock in that spot could deadlock.
Some of the warnings were bugs. A Color to UIColor cast that failed every time. Codable structs with defaults on immutable properties, so saved environment IDs never decoded. A homemade CGSize Codable conformance that shadowed Apple's. Ctrl and Alt toolbar buttons that I had built and never added to the toolbar.
What blocked it
The first upload is where the real reasons from a year ago showed up. App Store validation runs on the uploaded package after the compiler is done, and it checks things the compiler never looks at.
- The libssh2 framework's Info.plist had the literal text
ios_version_minas its MinimumOSVersion. Whoever built that binary never filled in the variable. Apple read it as a deployment target of 3.0. - libssh2 and OpenSSL shipped arm64e slices built with the iOS 16.2 SDK, which Apple now rejects.
lipostripped them. iPhones run the arm64 slice anyway. - All thirteen sticker pack icons had transparent backgrounds. Sticker icons can't have alpha, so they got flattened onto the dark brown already in the artwork.
sshd.xcframeworkreferenced a private symbol,___progname. The app never used sshd. Deleting the framework fixed it.
The validator doesn't give you the whole list. It reports one layer, you fix it and upload again, and the next layer appears. The private symbol only came up on the third upload. In 2025 I never got past the first one.
None of the eighty warnings were why it never shipped.
Around those fixes Fable 5 cleaned up the rest of the setup: a stale team ID, two macOS-only sandbox entitlements, a privacy manifest, the export compliance key, and the local network usage string the scanner needed. After the first build processed, Apple emailed about a missing 152 px iPad icon. Generating those turned up four alternate icons declared in the plist with no image files behind them.
Seven hours after my first message, build 0.1.2 (2) went into Beta App Review. The 8 GB download ate a good share of that.
First week of real use
I installed it from TestFlight on my phone the next day. Actually using it for a few days found four bugs. My server has 4 TB of storage and the dashboard said I was using 502% of it. The disk parser choked on the T suffix from df and fell back to a hardcoded 128 GB. Tapping the Live Activity dropped me on the dashboard and lost my session. My shell prompt's icons rendered as [?] until the terminal switched to the Nerd Font build of Monaspace. The New SSH Session sheet was white text on white.
Every session now exports VIA_TERMINAL=1, so the zsh config on my server can tell when I'm connecting from the app and give it its own prompt.
Build 0.1.3 (3) went out on August 8 with those fixes. The two Processing builds from 2025 are still there.