Skip to content
myrhex.dev

I build privacy software for Apple platforms, mostly in Swift, mostly from scratch. On X, I post daily news about SpaceX and SpaceXAI.

Searxly for macOS 1.1 shipped
Searxly Maximum 1.2 shipped
Searxly for iPhone 0.9.2 beta
TethrX 1.0 in review
Bulwark 0.5.0 open source
ScanRecords daily live
SCROLL

Most of what I make is one idea repeated: software that does not need to be trusted, because it cannot betray you.

01

About

I learn by building the entire thing. Not the demo, the thing: the app, the engine underneath it, the servers it talks to, the page that explains it. Nothing here was assembled from a template, which is slower, and the point.

I work alone, and I do every part myself: the Swift, the shaders, the cryptography, the servers, the support site, the words you are reading. One pair of hands is not a virtue on its own, but the seams between people are where software quietly rots, and this way there are no seams.

I am hard to satisfy, mostly with myself. The wind blowing across this page was rebuilt four times, because the first three were the wrong kind of wind. Most of what I make goes through that. It is the temperament everything below came from.

Privacy is not a niche I picked off a list. Software that watches people reads to me as a defect, in the same category as a crash. So I build the versions that cannot watch, and I put the proof in the architecture instead of in a promise.

Not all of it is software. I follow SpaceX and SpaceXAI closely, the launches, the engineering, where it is all heading, and I write it up every day. It is the same instinct as the code, wanting to get close to a hard thing and understand it all the way down instead of watching from across the room.

The short version

Everything here runs on your own machine unless it genuinely cannot, and each exception is printed next to the feature it belongs to.

That is most of the philosophy. The rest is just doing the work carefully enough that the claim stays true.

8weeks

for nearly everything on this page

257thousand

blocking rules compiled into the browser

1call

is all Maximum makes in its entire life

0requests

leave this page for anywhere else

02

Work

7 projects
01

Searxly

macOS browserShipped
Platform
macOS 15+, Apple Silicon
Stack
Swift · SwiftUI · WebKit · XPC
Engine
SearXNG on embedded CPython 3.12
Licence
PolyForm Noncommercial · AGPL parts

A native SwiftUI browser that bundles its own metasearch engine, so searching does not involve a company.

Searxly ships a full SearXNG instance inside the app bundle and runs it on your Mac. Your queries reach the engines they are meant to reach and nowhere else. There is no Searxly server in the search path, because there is no Searxly server.

Getting there meant deleting Docker. The engine now runs on a relocatable CPython 3.12.13 with every dependency installed as a prebuilt arm64 wheel and zero compilation, all twenty-odd Mach-O binaries codesigned with a hardened runtime so the whole thing survives being moved into an app bundle. That change was one commit: 797 lines added, 1,602 removed, across 21 files.

The rest is the browser you would expect from someone who cares about this. Tor with pluggable transports and per-tab circuit isolation, 257,000 blocking rules compiled across 14 lists, a native results page with client-side ranking, Reader Mode, on-device page translation, and a password vault. It is source available, notarized, and free.

02

Searxly Maximum

Hardened editionShipped
Price
$25 once, perpetual
Built from
One source tree, two targets
Licensing
Offline Ed25519, hardware bound
Network calls
Exactly one, ever

The same source tree, compiled into a second app that assumes you are actually being watched.

Maximum is one compile flag and one source of truth away from the free app. It forces maximum privacy and Tor at every launch, refuses to be downgraded, and strips out every surface the free app has that touches a network for a non-privacy reason.

The hardening is in the engine, not in JavaScript. WebKit's experimental and internal feature flags are enumerated at runtime and the privacy relevant ones turned off inside the engine: WebRTC, gamepad, NFC, serial, HID, USB, Bluetooth, battery, prefetch, prerender. Real Lockdown Mode and a Tor Browser style Standard, Safer, Safest slider sit on top. Every private call is guarded, so a missing symbol degrades instead of crashing. JavaScript shims stay as the floor, not the ceiling.

Because Maximum blocks native egress in Tor mode, Sparkle could never check for updates, which is a genuine hole. So the updater is replaced. It fetches the appcast over the fail-closed Tor lane, parses it, downloads over a delegated Tor session, and verifies the Ed25519 signature independently with CryptoKit before anything is trusted.

Licensing is offline. An Ed25519 signature verified against a bundled public key, bound to the machine. The app contacts a server exactly once in its life, at activation, and the privacy page says so in those words.

03

Searxly for iPhone

iOS appPublic beta
Platform
iOS 26+, iPhone and iPad
Architecture
Shared source group, UIKit browser layer
Search
Hosted instance, disclosed as a trust shift

The same browser on iOS, minus the parts that could not honestly come along.

A second target inside the existing Xcode project, sharing a synchronised source group with the Mac app and re-implementing the browser layer as UIKit representables.

It has no wallet, no crypto, no VPN, no Tor, and no bundled search engine. Partly App Review, partly physics. Search rides a hosted instance instead of one on your device, which is a real shift in who you have to trust. The product page says that plainly rather than burying it, because the alternative is a privacy app that lies in its first paragraph.

It is on public TestFlight now. The floor is iOS 26, which keeps the tester pool small and was a deliberate trade for Liquid Glass.

04

TethrX

iOS app + local bridgePublic beta
Bridge
Zero-dependency Node · Apache-2.0
Transport
ACP over HTTP/SSE, pinned TLS
Push
Hand-rolled APNs, ES256 + HTTP/2

Driving a terminal coding agent from a phone, over a connection with no middleman.

An iPhone app and a local daemon that pair over a QR code and talk directly. No relay, no account, no cloud.

The bridge is zero-dependency Node, which meant writing the parts a dependency would have handed me. Apple Push over hand-rolled ES256 JWTs and HTTP/2 straight to Apple. TLS pinned to a SHA-256 certificate fingerprint that travels inside the pairing QR code itself, so the very first connection is verified rather than trusted.

On the phone: a WidgetKit widget and Live Activities, a slash command palette, voice dictation, a project file browser jailed to the working directory, git review, Siri intents, Bonjour discovery, and a French localisation of about 200 hand-written keys.

05

Bulwark

Security libraryOpen source
Licence
MIT
Languages
Swift (complete) · Python · TypeScript
Detection
70 signatures, 15 languages
Tests
87 passing (Swift)

Prompt injection defence for agent loops. MIT, because this is not the kind of thing to keep.

A pipeline of sanitize, detect, spotlight, harden, validate, with 70 detection signatures across 15 languages, noisy-OR scored, folding leetspeak and composed obfuscation.

ToolGuard is the part I would keep if I could keep one thing. It guards the three choke points of an agent loop: the arguments going in, with exfiltration URL heuristics, invisible Unicode smuggling checks and a scheme allowlist; the outputs coming back; and the loop itself, with rate limiting, duplicate call detection, and a taint model that refuses any call above read-only once the agent has read untrusted content.

Rampart, added in 0.5.0, is deterministic zero-dependency PII redaction for email, phone, card via Luhn, SSN, IP and IBAN, with typed placeholders and rehydration. It is a clean-room reimplementation rather than a port, for licence reasons.

The Swift implementation is complete and covered by 87 passing tests. The Python and TypeScript ports have the detection layer but not yet ToolGuard.

06

ScanRecords

Public archiveLive
Tracked
31 companies, 96 documents, daily
Record
Git history, one commit per real change
Site
78 pages, 5 languages, no client JavaScript
Licence
MIT code, CC0 data

A public archive that records, every day, what the messaging platforms say they do with your messages, so that a quiet policy edit stops being quiet.

The EU's Chat Control derogation makes scanning private communications voluntary, so each provider decides for itself, and that decision, where it becomes public at all, becomes public as a small edit to a policy page. Nobody was keeping that record, and it is not a record you can reconstruct later. A measurement of 26 July can only be taken on 26 July.

So it is taken every day. At 06:17 UTC a zero-dependency tool fetches 96 tracked documents across 31 companies and 3 institutions, extracts the readable text, hashes it, and commits only when the text actually changed, so presentation churn never becomes a headline. Git history is the timestamped record, the repository is public so anyone can re-run it, and the Internet Archive is asked for an independent capture the same day. Alongside the policies it tracks 25 App Store privacy labels and 29 Play data safety declarations.

Most of the engineering is in not crying wolf. American CI runners were being served different pages than the European baselines, so every fetch now goes out through a relay in Paris. Google Play reshuffles its declarations on every request, so those are canonicalised before they are hashed. A failed fetch once got published as a policy change, so a capture that collapses to nothing can no longer overwrite a good one. When a record does turn out to be false it is withdrawn rather than deleted, and it keeps its page and its URL.

The site is 78 pages in five languages, generated by a script with no dependencies, and it ships no JavaScript at all except on the opt-in alerts page. It publishes observations and never conclusions: a recorded change means the document changed, and where the archive is silent it says so in those words, because silence measures disclosure and not behaviour.

07

searxly.app

WebsitesLive
Stack
Next.js 16 · Tailwind v4 · Vercel
Home page
17 segments over 3,400vh
Support auth
OTP + stateless HMAC, no accounts
Help assistant
No LLM, no network egress

A marketing site that is a scroll-driven film, and a support portal with no accounts.

The home page is not a page with animations on it. It is a seventeen-segment film across 3,400 viewport heights, with a CSS 3D MacBook whose lid opens on the hinge, a five-chapter iPhone act, and a canvas globe of 940 points drawing great circle arcs. Film grain, letterboxing and per-act colour grading throughout. Four locales, and untranslated routes noindex themselves rather than pretending.

The support portal has no accounts. Everything is email OTP and stateless HMAC tokens: the admin session, the fifteen-minute magic link, the per-ticket view key. It carries tickets, a public governance board, and translation across 20 languages, in 11 serverless functions, because the limit is 12.

The help assistant on every page has no model behind it. It fetches and indexes the site's own 28 pages in your browser and answers out of an IDF retrieval engine I wrote, with typo tolerance, light stemming, phrase bonuses and coverage weighting. No API key, no egress, no cost. A help widget should not be a data collection surface.

03

Approach

three positions
01

It should not need to be trusted

Trust is a promise, and promises break. I would rather remove the need: no server holding your data, no account behind it, no log to leak. When the dangerous part does not exist, nobody has to wonder about my character.

02

Write the dangerous parts yourself

The parts I do not understand are the parts that break. So the cryptography gets written by hand and tested until I know exactly how it fails, instead of imported and hoped about.

03

The limit sits next to the claim

Where something is built but not released, it says so. Where an app has to trust a server, that goes in the same paragraph as the feature, not in a policy nobody opens.

04

Stack

what I actually reach for

Languages

07
  • Swift
  • TypeScript
  • JavaScript
  • Python
  • SQL
  • Bash
  • Objective-C interop

Apple platforms

16
  • SwiftUI
  • UIKit
  • AppKit
  • WebKit / WKWebView
  • XPC Services
  • App Sandbox
  • CryptoKit
  • Keychain
  • Secure Enclave
  • NetworkExtension
  • Network.framework
  • WidgetKit
  • Live Activities
  • App Intents
  • Translation
  • codesign / notarytool

Cryptography

13
  • Ed25519
  • secp256k1
  • X25519
  • ChaCha20-Poly1305
  • AES-GCM
  • PBKDF2
  • HKDF
  • Keccak-256
  • HMAC
  • ES256 JWT
  • PKCS#8 / #12 / DER
  • Certificate pinning
  • Constant time comparison

Web

09
  • Next.js
  • React
  • Tailwind CSS
  • Canvas 2D
  • CSS 3D
  • IntersectionObserver
  • Web Push
  • i18n
  • Accessibility

Systems & infra

11
  • Node
  • Vercel
  • Postgres
  • Caddy
  • systemd
  • Tor + pluggable transports
  • IKEv2 / IPSec
  • SearXNG
  • OpenSSL
  • GitHub Actions
  • Playwright

Also

07
  • ONNX Runtime on-device inference
  • Model Context Protocol
  • BIP-32/39/44
  • EIP-1559 / 191 / 712
  • Threat modelling
  • AGPL / GPL compliance
  • Notarized distribution
05

Timeline

June to July 2026

Almost all of this happened in about eight weeks. I am not sure that is a virtue, but it is the truth, so here it is.

  1. June

    Jun

    App Sandbox and the XPC migration land. Every process spawn and file write in the browser starts going through a hardened helper.

  2. 18 Jun

    Keccak-256 and BIP-32 derivation bugs found. Every address the wallet had ever produced was wrong.

  3. 21 Jun

    Source published. PolyForm Noncommercial.

  4. 23 Jun

    Docker eliminated. SearXNG runs natively on an embedded, codesigned CPython.

  5. 27 Jun

    Deployment floor lowered to macOS 15. XPC helper hardened with a runtime code signature requirement and a symlink resolving path allowlist.

  6. 30 Jun

    iOS port begins. Scaffold to working native results page in a day.

  7. July

    2 Jul

    Audit tail closed. Search history encrypted, wallet egress gated, ranking regression suite written. It caught a live bug while being written.

  8. 5 Jul

    The WebRTC leak found and closed. Reader Mode and on-device translation ship.

  9. 6 Jul

    Public launch at 0.9.5, notarized, with a signed update feed. Per-user VPN certificates go live the same day.

  10. 8 Jul

    Integrated AI removed, about 10,000 lines deleted, and replaced with a local MCP server so your own model drives the browser instead of mine.

  11. 9 Jul

    First iOS TestFlight build. AGPL compliance remediated across the bundled engine.

  12. 10 Jul

    Bulwark 0.4.0 and 0.5.0 arrive, bringing ToolGuard and Rampart.

  13. 12 Jul

    Support portal live, including a public governance board proved by wallet signature.

  14. 13 Jul

    searxly.app rebuilt in Next.js and shipped.

  15. 16 Jul

    1.0 released, discovered to launch only on my own Mac, fixed, and re-shipped and verified the same day.

  16. 18 Jul

    Public iOS beta opens. The launch film and the no-LLM help assistant go to production.

  17. 19 Jul

    TethrX published to npm.

  18. 21 Jul

    Searxly 1.1 ships. This site goes live the same day.

  19. 23 Jul

    Apple grants the restricted web browser entitlement for passkeys and hardware security keys.

  20. 25 Jul

    TethrX 1.0 enters App Store review.

  21. 26 Jul

    ScanRecords goes live. A daily public archive of what the messaging platforms say about reading your messages, and of the day each sentence changed.

  22. 28 Jul

    The archive stops resting on a third party for who scans which service and reads the providers' own filings instead. Two of the four it had listed turned out to be wrong.

06

Elsewhere

No form, no newsletter, no analytics telling me you were here. No email and no phone number either, on purpose. These three are personal and they are the whole list: the products have their own channels, over on searxly.app.