Security architecture.

Ostler holds your entire digital life in one place. That is powerful and dangerous in equal measure. This page explains exactly how we protect it. No hand-waving, no “industry-standard encryption.” Specifics, and honest status labels on every claim.

The threat model is different here. A breach of your LinkedIn exposes one slice of your life. A breach of Ostler would expose everything – every relationship, every conversation, every pattern. We built the security around that reality.

The realistic threat is software, not magic AI. What threatens a local-first product is malicious code running on the same Mac, with your permissions, doing things you did not ask it to. The AI inside Ostler is an instructed insider: bounded tool calls, bounded data access, audited outputs. The unexpected attacker is everything else with a foothold on the host.

Figure 1.0  /  Security boundary One device. One owner.
SECURITY BOUNDARY YOUR MAC Secure Enclave Passkey · non-export Touch ID / Face ID SQLCipher DB AES-256 at rest FileVault below OSTLER CORE Local · localhost-only · no telemetry Auto-lock In-memory key wiped · ctypes.memset E2EE iOS APP Passkey via iCloud Keychain Realm · AES-256 Pinned TLS Self-signed Ed25519 Pubkey-pinned Home Wi-Fi only LAN No arrow leaves the boundary. No server. No telemetry.
No arrow leaves the boundary.

No cloud. A severely reduced attack surface.

Ostler does not connect to any external server. No cloud backend. No API endpoint. No telemetry. The databases, the AI models, and the processing pipeline all run on your Mac.

This eliminates the largest, most boring class of attack vector for personal data: server breaches, man-in-the-middle attacks, credential stuffing, insider access at the vendor, and government data requests against the vendor. There is no server to breach. There is no data to request.

Verify it yourself. Disconnect from the internet. Everything continues to work.

What this is not: a claim that nothing can go wrong. Removing the cloud closes the door an attacker most often walks through. It does not seal every window. The honest limits – what stays your responsibility – are spelled out in What this doesn’t protect against, below.

How authentication works

There is no password. We took passwords off the table entirely.

On first run, Ostler registers a passkey against your Mac’s Secure Enclave. From that moment on, unlocking Ostler is a Touch ID tap, a Face ID glance, or a double-click on your Apple Watch. The cryptographic proof of identity lives inside your Mac’s hardware security chip. It cannot be exported, phished, or copied to an attacker’s machine.

Creative Machines never sees a password because there is no password to see. We never receive a login token, a session cookie, or a hashed credential. There is nothing for us to lose in a breach because we hold nothing.

Your passkey syncs to your other Apple devices through iCloud Keychain, end-to-end encrypted by Apple. That is how the Ostler iOS app will unlock data from the same Hub without a second setup step.

What the passkey protects

Every Ostler database on disk is encrypted with a 32-byte data-encryption key (DEK). The DEK is generated on your Mac at install time, never leaves your Mac in plaintext, and is wrapped (encrypted) under a key derived from your passkey. Unlocking Ostler means: your biometric unlocks the passkey, the passkey unwraps the DEK, the DEK decrypts the databases. When the app locks, the DEK is wiped from memory.

When Ostler is locked

Ostler auto-locks after a configurable period of inactivity. On lock, the in-memory encryption key is overwritten. A stolen or lost Mac sitting on the attacker’s desk cannot yield plaintext without a live Touch ID / Face ID from you.

Most consumer software does not seriously model device theft – the cloud holds the real copy, so a stolen device is treated as a lost endpoint. We model it because here the device is the data, and the data is intimate. There is no cloud copy to fall back on. The auto-lock, the in-memory key wipe, and the requirement for a live biometric to re-unlock are designed around that reality, not bolted on after the fact.

Email is not the chokepoint here

A common pattern in “passwordless” products is to bind authentication or recovery to email – a magic link, a one-time code, a password-reset flow. It looks strong on the surface; there is no password to phish. The catch is that the security of the whole system inherits the security of the user’s email account. A compromised inbox is a compromised identity.

Ostler does not work that way. There is no password-reset email, no magic link, no email-bound recovery for the local product. The data-encryption key is issued by the Hub on your Mac at install time and wrapped under a key derived from your passkey, which lives in your Mac’s Secure Enclave. The only out-of-band fallback is the 12-word phrase you wrote down. The chain of custody never runs through your inbox.

Recovery phrase

There is exactly one fallback: a 12-word recovery phrase generated during setup. You write it on paper. You keep it somewhere safe. You never type it into iCloud, Dropbox, a password manager, or a photo.

The phrase is shown to you once, on a screen that blocks copy-paste, and never stored on disk afterwards. To be specific about what we use from BIP39 and what we don’t: we use its 2048-word English wordlist and its entropy-to-words encoding (128 bits of entropy plus a 4-bit checksum ⇒ 12 words). We do not implement BIP39’s PBKDF2 mnemonic-to-seed step – we treat the entropy as our recovery-key material directly, which is the right choice for a non-wallet system. Ostler is not a cryptocurrency wallet and we do not claim BIP39 wallet compatibility. We use the wordlist because it is publicly audited and ergonomically proven, not because we are interoperating with anything.

If you lose your Mac and your iPhone, and iCloud Keychain has not restored your passkey to a new device, the recovery phrase is how you get back in. It unwraps a second, independent copy of the same DEK.

If you lose the phrase and all your Apple devices and your Time Machine backup simultaneously, your data is gone. By us, by anyone. That is the price of real privacy – the same architecture that prevents us from reading your data prevents us from helping you recover it.

Encryption at rest

Your data is protected by multiple layers. Each row below shows the current, honest status – not what we intend, what is actually in the build:

ComponentEncryptionStatus
Full diskmacOS FileVault (AES-256-XTS)Live
Installer checks this is enabled
SQLite databasesSQLCipher (AES-256)Live in code
Deploys with the installer at launch
iOS app secure storeRealm (AES-256), device-bound keyLive
Voice-profile store encrypted on iOS today
iOS app main storePasskey-derived Realm key (shared with Hub)In development
Cross-platform spec signed off; iOS pairing flow next
Vector + graph databasesEncrypted APFS volumeIn development
Scripted volume creation lands in the installer
Local audit logSQLCipher-encrypted, append-onlyLive in code
Per-entry HMAC integrity chain is a planned upgrade
Time Machine backupsInherits FileVaultLive
Via macOS Time Machine encryption

Code and model integrity

Two pieces of Ostler arrive on your Mac from the internet at install time: the assistant binary itself, and the local LLM model weights. We handle the integrity of each differently because the trust shape is different.

The assistant binary ships as a signed tarball with a SHA-256 checksum published in a sidecar file. The installer downloads both, computes the hash of the tarball, and refuses to continue if the values do not match. Tampering between our release pipeline and your Mac – by an intermediary, by a compromised CDN, by any agent in between – is a hard install failure, not a silent compromise.

The model weights come from curated upstream registries (the Ollama registry, Hugging Face) over TLS at install time. We pin model names; we rely on the upstream maintainer’s tag-immutability discipline for what bytes those names resolve to. We are honest about the trust assertion: if a maintainer of an upstream we depend on shipped a malicious update under a tag we had pinned, fresh installs would pull it until the upstream caught the issue. We pin versions where we can, read changelogs, keep the model surface small. Tightening this further by pinning content digests is a hardening item on the post-launch list.

Hub and iPhone: hardened local channel

When the Ostler iOS app talks to your Mac Hub, the connection is designed to run over TLS with a self-signed certificate generated during install, with the iPhone pinning the certificate’s public key at pairing time so only your Mac can answer.

The cryptographic contract – pairing QR code format, WebAuthn handshake, HMAC-based proof of shared passkey, ten-minute pairing-token expiry – is locked in a normative cross-platform specification that was signed off on 2026-04-23 by both the Hub-side and iOS-side implementers. Every HKDF constant, wire-format byte, and test vector is fixed. Hub-side code-signing is the remaining blocker before iPhone-to-Hub pairing runs end-to-end (see below).

Network hardening

  • All services bind to localhost. Qdrant, Oxigraph, Valkey, the API gateway, the local LLM endpoint, the MCP service – none are reachable from outside your Mac. All Hub services bind to 127.0.0.1 (loopback only); none accept LAN connections. This protects against every attacker who is not already on your Mac. It does not isolate Ostler from other software running on the same Mac as you – see below.
  • JWT secrets validated at boot. Every service that participates in the gateway authentication chain refuses to start if its signing secret is missing, set to a placeholder, on a known-weak banlist, or shorter than 32 characters. A misconfigured deployment fails loudly at boot, not silently at request time.
  • No ports exposed to WAN. No UPnP. No port forwarding. Your router’s firewall is the perimeter.
  • Remote access via Tailscale only. If you want to access Ostler from your phone away from home, we recommend Tailscale (zero-trust, encrypted, no exposed ports).
  • iOS app connects over your home Wi-Fi. Once paired, your iPhone finds your Mac using the same local discovery that AirDrop uses. It never reaches out to the internet to find your Mac.

How the assistant is bounded

The AI inside Ostler is an instructed insider, in the phrasing of the callout at the top of this page. This section is what that means in concrete terms: what the assistant is allowed to do, what it is not allowed to do, and how its actions are recorded.

Workspace confinement. The assistant reads and writes inside a default-deny workspace. The directories that hold your credentials and your private keys – ~/.ssh, ~/.gnupg, ~/.aws, ~/.config, the system directories under /etc, /usr, /var – are on a static denylist that path-guards every file-touching tool. The assistant can read your messages, your email, and the documents you have asked it to read; it cannot, even by misadventure, read your SSH key.

Hardened binary. The assistant binary is built with macOS Hardened Runtime enabled, with the JIT, library-injection, and dyld-environment-variable capabilities denied at code-sign time. The standard process-level injection paths that work against ordinary Mac software – DYLD_INSERT_LIBRARIES hooks, JIT-mapped code injection, loader-environment-variable rewrites – do not work against the assistant. Code-signing trust is the gate; only the original binary runs.

Per-tool approval gate. Every tool call goes through an approval gate. In Supervised mode (the default), a tool that has not been pre-approved this session blocks until you say yes. Session-scoped allowlists do what the name says: they expire when the session ends, not when the assistant decides it has earned your trust forever.

Channel-driven default-deny. When the assistant is being driven by an incoming message – iMessage, WhatsApp, email – there is no human at the keyboard to approve a tool call. In that posture, the assistant cannot ask, so it does not run any tool outside a small read-only allowlist (search, lookup, fetch a public web page). A prompt-injection arriving by message cannot escalate to file writes, arbitrary network calls, or destructive shell commands; the shell-tool surface in this posture is bounded by a separate pre-approved command allowlist.

Tamper-evident audit log. Every tool call writes a record to a local audit log that uses a SHA-256 hash chain: each entry includes the hash of the previous entry, so a deleted or edited entry breaks the chain in a way that replay-validation detects. HMAC signing of each entry is supported as an additional hardening step. The audit log is local; it is not shipped anywhere.

Private-by-default conversations. Conversations between you and the assistant are stored on your Hub and marked private by default. Content tagged at the most sensitive privacy level (full transcript bodies you have shared in confidence) is withheld from query responses unless the calling client explicitly opts in. The default API path returns metadata, not bodies.

Privilege boundaries

Ostler runs as your user account on your Mac – not as root, not as a system service. The orchestrator, the API gateway, the local databases, and the inference processes all run inside your user’s permission scope. There is no LaunchDaemon shipping with the installer, and no background process that survives logout.

The installer asks for an administrator password once, at install time, for the system-level operations that macOS requires admin for: changing power-management settings so the Hub stays reachable to your iPhone when the Mac is idle (disable sleep on AC, enable wake-on-magic-packet), and installing the supporting packages (Homebrew, Ollama) that ship as standard macOS CLIs. After install, no part of Ostler asks for elevated privileges to run, and the application has no path that escalates on its own.

This bounds the blast radius of a bug or a successful attack on Ostler itself: it inherits your user’s reach, not the system’s. It does not protect against malware that has already obtained your user’s permissions through some other vector – that is the surface the next section is about.

What this doesn’t protect against

Closing the cloud closes the biggest, most boring class of attack – the kind that exposes a million people at once. It does not mean nothing can ever go wrong. We would rather tell you the limits than let you discover them.

Other software running on your Mac

This is the realistic threat surface for a local-first product, and we are explicit about it. If a piece of malware reaches your Mac through a malicious browser extension, a poisoned download, or a compromised app from outside the App Store, it inherits your user’s ability to talk to localhost. The encryption-at-rest layer protects against physical theft and against your data leaving the device, but it does not isolate Ostler from other software you have given permission to run. Treat your Hub Mac the way you would treat a password manager or a banking app: don’t install random utilities, don’t approve installer prompts you didn’t initiate, and ideally use a Mac that mostly runs Ostler and not much else.

Supply-chain compromise of our dependencies

Ostler runs on Ollama, an LLM model file, a Python runtime, and a small set of Python packages. We don’t write those, we use them. If any of those upstream projects shipped a malicious update tomorrow, fresh installs – ours, yours, every other user’s – would be exposed until the issue was caught. We pin versions, we read changelogs, we keep the dependency surface as small as we can. We are not going to pretend the risk is zero. The same supply-chain caveat applies to any software you ever install, anywhere.

You

The recovery phrase is the worst-case backdoor. If you write it on a sticky note, take a photo of it, paste it into a cloud notes app, or read it out on a video call, the phrase becomes the attacker’s shortest path. We make it easy to do the right thing – the screen blocks copy-paste, the recovery doc explains the threat – but the final link in the chain is you.

This is the price of a system that holds the keys on your hardware, not ours. We can architect the inside; we can’t architect around bad operational hygiene. The mitigation is honest documentation, not a promise we can keep on your behalf.

Independent audit

We are engaging senior security advisors and scoping an independent security audit from a recognised cybersecurity firm. The scope covers authentication, data handling, storage encryption, network posture, and dependency analysis. The report will be published here when complete.

We chose a professional audit over relying on community code review because an expert review is more rigorous than hoping someone reads the code. Trust should be verifiable, not assumed. “We promise not to look at your data” is what every cloud company says. “We architecturally cannot look at your data, and here is the auditor’s report proving it” is what we are aiming for.

The architecture is intentionally simple. Passkey-primary auth via Apple’s own frameworks. Standard cryptographic primitives (HKDF-SHA256, AES-KW RFC 3394). Local services on 127.0.0.1. Local Ollama inference. There is very little novel cryptography to get wrong because the primary security mechanism is not having a network connection to begin with.

For the technically curious

Authentication

Passkey (WebAuthn Level 2) registered against Apple’s platform authenticator via ASAuthorizationPlatformPublicKeyCredentialProvider, using the PRF extension. Requires macOS 15+ / iOS 17.4+. The PRF output is a pseudorandom value bound to the authenticator, the credential, and the relying-party identifier – non-exportable from the Secure Enclave.

Helper architecture

A small Swift helper binary owns every WebAuthn call and talks to the Python side via one-shot JSON-RPC. Pure AuthenticationServices + Security.framework, no third-party Swift packages.

Relying party

rp_id = creativemachines.ai. Tied to the company domain, not the product name, so a future product rename cannot invalidate existing users’ credentials.

Key derivation

HKDF-SHA256. Domain-separated info strings use the creativemachines/ namespace for the same rebrand-safety reason. No PBKDF2 anywhere in the primary path – the PRF output is already a full-entropy key.

Key wrapping

AES Key Wrap, RFC 3394 unpadded variant. A 32-byte DEK wrapped under a 32-byte KEK produces a 40-byte blob with a built-in integrity check. A wrong KEK fails to unwrap – it does not return garbage plaintext.

Recovery

12-word phrase from the same publicly audited 2048-word English list as BIP39, 128 bits of native entropy plus a checksum word. The 16-byte entropy feeds HKDF-SHA256 with the same shared salt, under a distinct info string, to derive an independent recovery KEK. No PBKDF2 mnemonic-to-seed step – a second KDF over already-full-entropy input adds no security in this threat model. We borrow the wordlist; we do not claim BIP39 wallet compatibility.

At-rest encryption

SQLCipher (AES-256) for the Ostler databases on the Mac Hub. Realm (AES-256) for the iOS app. Keychain items scoped AccessibleWhenUnlockedThisDeviceOnly, Synchronizable = false – wrapped DEKs never travel in Time Machine or Migration Assistant.

Memory handling

Long-lived session key held as a mutable bytearray and zeroised via ctypes.memset on lock or timeout. Short-lived immutable copies in Python are honestly documented as best-effort only, not claimed as guaranteed scrubbed.

Transport

TLS with a self-signed Ed25519 server certificate generated at install. Public-key pinned by the iOS app at first pair. No unpinned HTTP. No application-layer fallback channel.

The full cross-platform cryptographic contract between the Mac Hub and the iOS app, including every constant, test vector, and wire-format byte, is available for independent review.

Current build status – honest line-by-line

Transparency means admitting exactly where each piece stands today, with a specific blocker named for anything not yet live:

  • FileVault checkLive Installer verifies FileVault status and warns if disabled.
  • Passkey helper (Swift binary)Live in code Real ASAuthorizationPlatformPublicKeyCredentialProvider + PRF extension via macOS 15 AuthenticationServices. Builds and runs. Keychain operations smoke-tested against real Security.framework on 2026-04-23.
  • Python auth orchestratorLive in code HKDF-SHA256 key derivation, AES-KW wrap / unwrap, recovery-phrase generation and validation against the public 2048-word wordlist, setup wizard, recovery CLI, all wired through to SQLCipher. Test suite passing at 299 tests.
  • SQLCipher encryptionLive in code PRAGMA-injection-guarded connection factory and migration tool. Consumed by the conversation pipeline and the API layer. Ships with the installer.
  • Recovery phraseLive in code 12-word phrase from a public 2048-word English wordlist (the same list popularised by BIP39, used here for its auditability), 128-bit entropy, checksum-validated. Setup wizard displays once with paper-only guidance; recovery CLI re-binds to a new passkey on the new device.
  • Auto-lockLive in code Configurable timeout with a 5-minute minimum, ctypes.memset scrub on lock, typed-exception re-unlock callback.
  • Local audit logLive in code SQLCipher-encrypted, symlink-TOCTOU-hardened, event-type whitelist, concurrent-writer lock, query-limit clamping. Per-entry HMAC integrity chain is the planned upgrade – audit-log writes are already covered by the DB-level encryption.
  • Hardened inter-service TLSLive in code Ed25519 self-signed CA + server + client certificates generated by installer; the installer registers signed LaunchAgents under ~/Library/LaunchAgents/ with path-injection guards on all certificate paths.
  • Developer ID code-signing of the passkey helperPlanned for launch Apple’s AuthenticationServices refuses ad-hoc signed binaries for real register / assert operations – the call silently never completes. The Creative Machines Developer ID certificate is now in place and notarises the assistant binary; the remaining work is signing the passkey helper itself, wiring its entitlements file, and serving the apple-app-site-association document from creativemachines.ai.
  • iOS app passkey integrationIn development Cross-platform spec signed off 2026-04-23 by both implementers; the iOS-side WebAuthn client, pairing UI, and Realm-key derivation from the shared passkey are the next iOS workstream. The iOS secure-store Realm is already encrypted today; moving its key onto the passkey-PRF path is what this workstream completes.
  • Encrypted APFS volume for Qdrant and OxigraphIn development Scripted APFS volume creation with installer-managed mount points under ~/.ostler/. No technical blocker – prioritised after SQLCipher and passkey work, which came first because they protect the larger data surface.
  • Independent security auditScoped Senior advisors engaged; scoping calls held. Engagement with the audit firm not yet signed.
  • Audit-log HMAC integrity chainPlanned Append-only SQLCipher storage is the current protection; per-entry HMAC linking is the hardening step on the post-audit list.

Responsible disclosure

If you think you have found a security vulnerability in any part of Ostler – the Mac Hub installer, the iOS app, the passkey helper, the Sparkle update pipeline, or any related infrastructure – please report it to [email protected].

What we promise in return:

  • Acknowledgement within 72 hours. A human reads every report.
  • A real conversation. No auto-responders, no triage forms, no bug-bounty paperwork. You talk to an engineer.
  • Public credit, if you want it. We will name you in the release notes for the version that fixes the issue. Pseudonyms and anonymous credit are fine too. If you prefer no credit, we will respect that.
  • A fair window to fix. We ask that you give us a reasonable time to ship a patch before public disclosure. In return we commit to not using legal threats against good-faith researchers.

What we ask in return: do not access other users’ data, do not disrupt our services, and do not demand payment as a condition of disclosure. We do not run a paid bug-bounty at launch – if that changes, this page will say so.

For encrypted reports, our PGP public key is published at /security.asc. The full disclosure policy is also machine-readable at /security.txt per RFC 9116.

The security story is the privacy story. Every competitor sends your data to the cloud and promises to protect it. We keep your data on your hardware and prove it cannot leave. That is not a feature. It is the architecture.

Privacy overview What Ostler knows

Architecturally cannot look. Audit pending.

Specifics  ·  Not hand-waving