Conversation
FTWKit is a Swift package that builds and tests on Linux and Apple platforms. CryptoKit supplies the primitives; swift-crypto stands in on Linux only. The Cacophony vectors and the interop vectors that srcfl/ftw generates from the web app's code pass byte for byte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
Enrollment parsing, the box code, the PRF derivations, the vault and the recovery copy follow the web app byte for byte. Vectors produced by running the web app's own identity code prove it: a copy the web app sealed opens here under the same passkey, and the escrow ids and write keys match. The escrow client pads, signs and versions its requests the way the service expects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
RelayCarrier, NoiseCarrier and Session follow the web app's carrier and session rules: rotating rendezvous handles with bounded epoch correction, a silent box ending the handshake and a retry, requests that always settle, one API call on the wire at a time, and the three command deadlines. A SimulatedBox speaks the same frames for the demo and the tests; the tests drive the whole stack through fake sockets on a manual clock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
A live run against a box built from srcfl/ftw, over the production relay, found that the box drops a hist.query or price.get whose times carry a fraction: it decodes them into int64. Times now go out whole, and the simulated box refuses fractions the same way so the unit tests hold it. LiveBoxTests pairs with a freshly minted code and exercises the stream, the API passthrough, the plan, history, the E_USE_CMD refusal and a mode command. It runs only when FTW_LIVE_URL is set; on Linux, whose Foundation has no WebSocket client, it reaches the relay through a local bridge named by FTW_LIVE_RELAY. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
SiteModel keeps freshness honest the web app's way: a carrier is claimed only once it delivers a reading, ages come from box uptime, and a quiet stream stops reading as live. The cached snapshot is sealed on disk under a key kept beside the vault, so a cold start paints before any passkey prompt. Feature models cover the plan and modes, prices, energy by day, history tiles with a cache, the charger sheet with its commands and goal, sharing, notification rules, restart, pairing, recovery and the demo. Every sentence is ported from the web app and pinned by tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
The native app is now pure Swift on Apple platforms. FTWKit moves to appleApp/FTWKit so the Xcode project can sit beside it, and the app in appleApp/FTW covers every screen the web app has: pairing (camera, a picture of the QR on a Mac, passkey recovery, the demo), Now (the sentence, the energy flow, price, the plan brief, today, the fuse, the live line and the charger sheet), Plan, History with daily energy, and Box (access, notifications, restart, the sealed copy, sign out). The Keychain holds the store, passkeys run through AuthenticationServices with PRF on the web app's relying party and salt, and a Mac gets a menu bar glance. Three pieces of logic moved into FTWKit with tests so both apps say the same thing: the freshness band's wording, the price card's cheapest two hours and tones, and the sealed copy switch. CI now builds the app, unsigned, for the iOS Simulator and for macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
Xcode 26 refuses to resume a continuation with the platform's passkey credential, which is not Sendable. The delegate now copies the credential id and the PRF output into plain values on the main actor and passes those. The Linux test client stops mixing an Int literal into a UInt8 array, which Swift 6.1 does not accept. iOS and macOS are pure Swift now, so iosApp/, shared/src/iosMain and the iOS framework targets in shared/build.gradle.kts go. Android keeps the KMP core unchanged. README and CLAUDE.md describe the Apple app, its scope as chosen by Fredrik on 2026-09-25, what is proven and what still needs a device, and keep the Android gate as it was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
frahlg
force-pushed
the
claude/native-swift-ftw-app-d7j9w4
branch
from
September 25, 2026 06:54
4cd5ac2 to
2a24e9a
Compare
Debug builds take -FTWDemo YES and -FTWTab <now|plan|history|box>, so appleApp/scripts/demo-screenshots.sh can open every screen of the simulated home and save a picture of each, dark and light. CI runs it after the build and keeps the pictures as an artifact. It is evidence for whoever reviews the screens, not a gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
A pure Swift FTW client for iPhone, iPad and Mac. It replaces
iosApp/and the Kotlin Multiplatform dependency on Apple platforms. Android keeps the KMP core unchanged.Scope set by Fredrik on 2026-09-25: Swift for iOS and macOS, replace iosApp directly, cover the whole web app, and derive the wrap key from the passkey the way the web app does (HKDF), so one passkey opens a home in both. Native pairings made before this change scan the QR again.
Layout
appleApp/FTWKit: Swift package with everything that is not a pixel. CBOR, frames, Noise IK, transport, relay and Noise carriers, the session, pairing, vault, PRF derivations, recovery blob, escrow, the simulated box for the demo, and the state every screen reads. Builds and tests on Linux and on Apple platforms (CryptoKit there, swift-crypto on Linux only).appleApp/FTW: the SwiftUI app. Pair, Now (sentence, energy flow, price card, plan brief, today, fuse, live line, charger sheet), Plan, History with daily energy, Box (identity, access and viewer invites, notification rules, restart, sealed copy, sign out). A Mac also gets a menu bar glance.appleApp/FTW.xcodeproj: hand written, objectVersion 77 with a synchronizedFTW/folder and FTWKit as a local package. Bundle idenergy.ftw.app, iOS 18 and macOS 15.iosApp/,shared/src/iosMainand the iOS framework targets inshared/build.gradle.ktsare removed. README and CLAUDE.md describe the new split.Evidence
swift testinappleApp/FTWKit: 95 tests green on Linux (Swift 6.3) and on macOS in CI (Xcode 26.3, CryptoKit)../gradlew :shared:jvmTestafter removing the iOS targets: 41 passed, 0 failed, 4 skipped (the live box tests, which needFTW_LIVE_BOX).wss://relay.ftw.energy: paired, streaming after 1.2 s,/api/statusover the passthrough, plan, history tiles,site.mode.setapplied. That run found a real bug (times sent with a fraction) that is fixed here.State at handoff
Work moves to Fredrik's Mac from here. This session stops pushing.
Passkeys.swift(a non Sendable credential crossing a continuation). That is fixed in 2a24e9a. The run for the latest head had not finished at handoff, so the app compiling end to end is not yet confirmed. Expect possibly a few more strict concurrency errors in Xcode.Continue on a Mac
git fetch && git checkout claude/native-swift-ftw-app-d7j9w4cd appleApp/FTWKit && swift testappleApp/FTW.xcodeproj, pick your team under Signing & Capabilities, build the FTW scheme for an iPhone simulator and for My Mac. Fix whatever Xcode flags.appleApp/scripts/demo-screenshots.shphotographs every tab of the demo after a Debug build..well-known/apple-app-site-associationto app.ftw.energy (srcfl/ftw-webapp) with<TEAM_ID>.energy.ftw.appunderwebcredentialsandapplinks.Open
🤖 Generated with Claude Code
https://claude.ai/code/session_015czRWjvgq7kpxB3pdJXm4t