Inspiration

Students switch between essays, code, practice and everyday obligations many times a day. The expensive part is not the interruption; it is rebuilding what you had decided, what failed and where to start again. We wanted a calm place to put that context down, without another guilt-inducing task list.

What it does

Tether holds each thing you are in the middle of as a thread with one concrete next move, a short "what you'll wish you remembered" note and optional links. Coming back opens a focused return card instead of a dashboard. Parking a thread adds a checkpoint rather than overwriting earlier thinking. One thread is active at a time, a five-minute filter finds small windows, and there is a menu-bar entry, keyboard shortcuts and full Markdown export. Notes stay on the Mac and are never sent to RevenueCat or an AI model.

How we built it

SwiftUI and AppKit on macOS 14+, built with Swift Package Manager. A separate, UI-free TetherCore module holds the domain rules (checkpoints, one-active-thread transitions, the free limit, export) and is covered by standalone checks. Persistence is atomic JSON in Application Support; unreadable data is preserved, and failed saves roll back.

How RevenueCat is used

The app uses RevenueCat's purchases-ios SDK 5.90.2, not a REST stand-in:

  • Purchases.configure with a public SDK key (the RevenueCat Test Store for this entry);
  • offerings() loads the current offering; the Plus screen renders its Monthly ($9.99/month), Yearly ($79.99/year) and Lifetime ($99.99) packages from the returned products, with no hardcoded prices;
  • purchase(package:) runs the purchase; on the Test Store the SDK shows its own confirmation;
  • access comes only from CustomerInfo.entitlements["plus"].isActive, refreshed on app activation and at the known expiry date, and through the CustomerInfo delegate;
  • restorePurchases() restores access and the app confirms the result.

Free: three open threads and the latest checkpoint per thread. Plus: unlimited open threads and the full checkpoint trail. If Plus ends, nothing is deleted or locked, and export always includes every checkpoint.

Verified in the running app on September 22, 2026 and shown in the video: offerings load, a Test Store purchase of Monthly activates plus, the fourth thread that the free plan refused is saved, the full trail appears, and Restore purchases confirms Plus. Test Store purchases are sandbox transactions with no real charge.

Challenges we ran into

Recording a real purchase honestly. We captured only Tether's own windows with ScreenCaptureKit and drove the app and RevenueCat's Test Store alert through macOS accessibility, so the film is one continuous recording rather than mockups. The purchase run also exposed three rough edges we fixed: a clipped paywall subtitle, a stale free-limit notice after unlocking, and a restore with no visible result.

Accomplishments that we're proud of

A useful free app first, with a paywall that only adds room: your draft survives the free limit, purchase unlocks it in place, and expiry never holds notes hostage.

What we learned

Entitlement state needs refreshing at the moments it can change (activation, expiry), not only at launch. And monetization feels fair when the free tier is complete on its own.

What's next for Tether

A production App Store build with Apple products, notarized distribution, and user testing of whether return cards actually shorten restarts. No revenue, users or productivity outcomes are claimed today.

Try it

macOS 14+: swift run Tether from https://github.com/ToukoUrsin/tether (MIT). Purchases need a RevenueCat public SDK key in Settings or REVENUECAT_PUBLIC_KEY.

Team and AI disclosure

Touko Ursin, solo, Aalto University student (Next Gen category). Development was assisted by OpenAI Codex and Claude (design, code generation, debugging, test preparation, and the video edit). Video narration uses an ElevenLabs stock voice. The app contains no AI features.

Built With

  • appkit
  • macos
  • revenuecat
  • swift
  • swiftui
Share this project:

Updates

Submission history