NOBS

NOBS — No-BS Personal Assistant

A privacy-first, Apple-ecosystem AI assistant that acts like a real assistant: it makes phone calls, browses the web, controls your smart home, manages reminders, screens unknown callers, and chats with you over iMessage — all while keeping every learned fact on your own device.


Architecture Overview

┌─────────────────────────────────────────────────┐
│                   NOBS Apps                     │
│   iOS App  │  macOS App  │  watchOS Complication │
└────────────┬────────────────────────────────────┘
             │  Swift Package (NOBSKit)
┌────────────▼────────────────────────────────────┐
│  NOBSAssistant  ◄──  Central Coordinator        │
│  Routes intents to the right module             │
└──┬──────┬──────┬──────┬──────┬──────┬──────────┘
   │      │      │      │      │      │
NOBSCore  │  NOBSCallKit  │  NOBSHomeKit  │
Local AI  │  (CallKit +   │  (HomeKit)    │
Client    │   Google Voice│               │
          │               │               │
     NOBSiMessage   NOBSDatabase   NOBSReminders
     (Messages.app  (Work / Personal  (EventKit)
      integration)   CoreData stores)
                            │
                      NOBSSecurity
                   (Keychain + LocalAuth)

Key Design Principles

Principle Implementation
On-device privacy All learned context is stored in encrypted Core Data databases on the user’s device. Nothing is sent to third-party clouds.
Local model The AI runs on a user-owned server. Apps communicate via a local network REST/WebSocket API (NOBSCore).
Work / Personal separation Two isolated Core Data persistent stores — every piece of information is tagged to a context at write time.
Modular Each capability lives in its own Swift target so individual features can be shipped, tested, and updated independently.
Keychain for all secrets OAuth tokens and API keys are stored in the iOS/macOS Keychain via NOBSSecurity.KeychainStore with .afterFirstUnlockThisDeviceOnly protection so secrets never migrate off device.
Biometric gate NOBSSecurity.LocalAuthGate wraps LAContext to enforce Face ID, Touch ID, or passcode authentication before sensitive operations (calls, messages, HomeKit) are executed.

Modules

NOBSCore — AI Model Client

Connects to a locally hosted LLM server (Ollama, LM Studio, or any OpenAI-compatible endpoint).

NOBSAssistant — Central Coordinator

Receives AssistantIntent values and dispatches them to the right module handler.

NOBSCallKit — Phone Calls & Call Screening

NOBSiMessage — iMessage Integration

NOBSHomeKit — Smart Home

NOBSDatabase — Work / Personal Data Stores

NOBSSecurity — Keychain & Biometric Authentication

Provides the security primitives used throughout the NOBS suite.

NOBSReminders — Reminders & EventKit

NOBSVoice — Google Voice API


Requirements


Getting Started

# Clone the repo
git clone https://github.com/acburgess25/NOBS.git
cd NOBS

# Open in Xcode
open Package.swift   # library-only work

1 — Configure your local LLM endpoint

Edit Sources/NOBSCore/ModelClient.swift:

ModelConfiguration.localhost   // http://127.0.0.1:11434 by default
// or supply your server IP:
ModelConfiguration(localEndpoint: URL(string: "http://192.168.1.10:11434")!)

Install Ollama on your server and pull a model:

ollama pull llama3

2 — Google Voice API

  1. Create credentials in Google Cloud Console.
  2. Enable the Google Voice and Cloud Speech-to-Text APIs.
  3. Pass credentials to VoiceClient (store clientID / clientSecret in the iOS Keychain — never in source files).

3 — Apple Entitlements

In your Xcode app target, enable:

Add NSRemindersUsageDescription to Info.plist.


iCloud Sync

⚠️ iCloud Sync is OFF by default and must be explicitly enabled by the user.

By default, NOBS stores everything on-device only. iCloud sync is an opt-in feature that must be presented to the user with a clear disclosure before activation.

What iCloud Sync means

  On-Device Only (default) iCloud Sync
Data stored on your device
Data uploaded to Apple’s servers
Syncs across your Apple devices
Apple’s iCloud Privacy Policy applies
Work & Personal kept separate ✅ (separate CloudKit zones)

How to enable (developer)

// 1. Show the disclosure FIRST — required before enabling iCloud.
print(iCloudDisclosure.userFacingWarning)
// or use iCloudDisclosure.fullExplanation for a dedicated settings screen

// 2. Only after the user explicitly confirms:
try NOBSDatabase.shared.setup(
    storageMode: .iCloud(containerID: "iCloud.com.yourcompany.nobs")
)

Disclosure strings

iCloudDisclosure provides three ready-made strings you must present before enabling iCloud:

Required entitlements for iCloud Sync

Add to your app target in Xcode:


Security

Keychain (NOBSSecurity.KeychainStore)

All sensitive string values — OAuth access tokens, refresh tokens, and token expiry dates — are stored in the system Keychain using Apple’s SecItem APIs.

// In production always use the default VoiceTokenStore (backed by the Keychain):
let client = VoiceClient(credentials: creds)          // tokenStore defaults to VoiceTokenStore()

// In unit tests, pass nil to skip Keychain access:
let client = VoiceClient(credentials: creds, tokenStore: nil)

Protection class used: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly

Property Value
Accessible after first unlock ✅ (background app access OK)
Migrates to new device via backup
Syncs via iCloud Keychain
Available on iOS Simulator

Biometric / Passcode Gate (NOBSSecurity.LocalAuthGate)

Wrap any sensitive operation with LocalAuthGate to require Face ID, Touch ID, or the device passcode.

let gate = LocalAuthGate(
    policy: .biometricOrPasscode,      // or .biometricOnly
    reason: "Authenticate to place a call",
    sessionDuration: 300               // re-authenticate after 5 minutes
)

// In your app / view model:
try await gate.requireAuthentication()
// … perform sensitive operation …

// When app goes to background — force re-authentication next time:
await gate.invalidate()

Security principles