WRITING
Open-Sourcing Two Native macOS Apps: Ask Claude and HydroMac

My desktop runs a small fleet of native macOS apps I built for myself — one for asking AI, one for water-engineering calculations, one for document processing, one for watching positions. All small SwiftUI tools, all in daily use for a long time. This week I cleaned up two of them and open-sourced them: Ask Claude and HydroMac (水利工具箱), with a third, DocTools, along for the ride. This post covers what they are, the architecture they share, and the part of open-sourcing that actually took work — scrubbing the data.
Ask Claude: a native chat window for Claude subscribers
Repo: github.com/zengtianli/ask-claude
The pain point is specific: I have a Claude subscription (Pro/Max), and asking questions through the Claude Code CLI in a terminal works fine — but I always wanted a proper window at hand. Meanwhile almost every Claude client out there wants an API key, which is a separate, token-metered bill your subscription quota can't pay.
Ask Claude never touches the API: it spawns the claude binary you already have logged in (claude -p --output-format stream-json --include-partial-messages) as a subprocess and parses the streaming JSON line by line — session_id means "connected", the model name means "opus is thinking", each text_delta renders incrementally, and multi-turn memory rides on the CLI's own --resume mechanism. Which means:
- Zero API key, zero extra billing. If
clauderuns in your terminal, this app runs — on the same subscription quota. - No chat history of its own. Sessions are managed entirely by the Claude Code CLI, exactly as if you were using the terminal.
- Pure SwiftUI, one small binary. No Electron, no web view, no background daemon. The release zip is 209KB.
Requires macOS 15+ (Apple Silicon) and an installed, logged-in Claude Code CLI. Defaults to Opus; one defaults write switches the model.
HydroMac: a SwiftUI shell over a Rust compute core
Repo: github.com/zengtianli/hydro-mac
This one is my day job. Eight water-engineering calculators in one .app: annual water-resources report queries, river pollutant-carrying capacity (1-D decay model), water-efficiency assessment (AHP + CRITIC combined weighting), joint reservoir dispatch, plain-river multi-district water balance, daily irrigation demand, a full district rainfall pipeline, and geocoding with coordinate-system conversion.
Architecturally it's the same idea as Ask Claude in a second shape:

The shell is always native SwiftUI (compiled straight with swiftc — there isn't even an xcodeproj); the compute core is pure Rust (hydro-cli), driven via Foundation.Process with a JSON envelope {ok, data, error} over stdin/stdout. The binary is embedded in .app/Contents/Resources, so the single .app is self-contained and fully offline — which matters in this industry, because field survey sites often have no network.
Numerical reliability is life-or-death for tools like this: the repo ships 20 golden numerical regression cases (any change to the calculation math must pass all of them) plus 64 cargo unit tests.
The real work of open-sourcing: scrubbing the data
Flipping a private repo to public takes one click — but doing that would have been an incident, not a release. HydroMac's sample data and golden cases came from real engineering work: real reservoir names, real hydrological districts, real companies' water-intake ledgers — present in git history since the very first commit. That leaves exactly one correct path: a fresh clean repo plus fully synthetic data.
The effort was far bigger than I estimated:

The most counterintuitive leak deserves its own paragraph: pinyin initials. The district output codes were literally the pinyin abbreviations of real place names — every Chinese name had been scrubbed, while the abbreviations sat untouched in constant tables, the parser, and the golden cases. In the same family: .pyc caches embedding the build machine's absolute paths (actually caught inside another app's release zip), regional abbreviations in CSV headers, names embedded in xlsx cells. The lesson in one sentence: sanitization must sweep the non-Chinese forms — pinyin abbreviations, coordinates, binary strings, cache files. None of them can be waved through on intuition.
How small can native apps be
All three apps are ad-hoc signed with no paid developer certificate, and the release zip sizes are the direct dividend of a native stack:

The third repo that came along is DocTools: a batch document toolbox (clean, convert, merge, split, preview), SwiftUI shell + Python engine, the same process-plus-JSON contract, 429KB release zip.
Take them
All three repos are MIT-licensed, with arm64 zips attached to the Releases page. Since they're ad-hoc signed, clear the quarantine flag once before first launch:
xattr -cr "/Applications/Ask Claude.app"
or right-click → Open, then allow it under System Settings → Privacy & Security. If you'd rather not trust prebuilt binaries, each repo builds from source with a single ./build.sh.
- Ask Claude — github.com/zengtianli/ask-claude (macOS 15+, needs Claude Code CLI + subscription)
- HydroMac — github.com/zengtianli/hydro-mac (macOS 14+, self-contained, offline)
- DocTools — github.com/zengtianli/doc-tools (macOS 15+, needs uv)
Issues and PRs welcome.