A 1.4 MB Kipferl without putting Rust on your machine
Rust gave Kipferl a much better maintenance story, but the complete runtime grew with Ratatui, Rustls, SQLite, archives, and data-format parsers. Version 0.6 takes most of that cost back when an app does not use those capabilities.
The constraint mattered more than the linker
Traditional tree shaking links a fresh executable for every app. That would make users install Rust, Cargo, a C compiler, and target linkers—the opposite of Kipferl's developer-experience goal. A build should remain one fast command and produce one target-specific file with no runtime dependency.
Kipferl therefore ships two prebuilt Rust runtimes. The core profile contains PocketPy and the dependency-light CLI surface. The full profile adds maintained implementations for SQLite, HTTPS, Ratatui input, regex, archives, crypto, timezone data, YAML, TOML, and KDL. Cargo features remove those complete dependency trees when we build core; there are no empty placeholders in the small artifact.
Conservative by construction
1. Analyze
A small lexer reads static imports while ignoring comments and quoted strings.
2. Select
Common modules choose core; optional capabilities choose full with an explicit reason.
3. Package
The existing loader receives the selected prebuilt runtime and transformed app.
Dynamic imports, relative imports, exec, andeval deliberately fall back to full. The build log says which profile was chosen and why. --full-runtime is the escape hatch when application logic hides an import from static analysis. A false positive costs bytes; a false negative could ship a broken app, so the bias is intentional.
✓ Runtime profile full (complete compatibility)
Full runtime: sqlite3 requires the SQLite capabilityThe measured result
| Apple Silicon artifact | Bytes | Change |
|---|---|---|
| Full runtime | 4,497,440 | Compatibility baseline |
| Core runtime | 1,130,352 | 74.9% smaller runtime |
| Full standalone app | 4,817,925 | Loader and minimal source included |
| Core standalone app | 1,450,837 | 69.9% smaller app |
Local v0.6 release-profile measurement on macOS ARM64. Source size and target architecture change the exact result; four-target CI enforces a 2.5 MB ceiling for every core runtime.
Core runtime across every release target
| Target | Full | Core | Reduction |
|---|---|---|---|
| macOS ARM64 | 4,497,440 | 1,130,352 | 74.9% |
| macOS x86_64 | 5,056,944 | 1,183,140 | 76.6% |
| Linux ARM64 musl | 4,738,296 | 1,316,512 | 72.2% |
| Linux x86_64 musl | 5,451,504 | 1,349,904 | 75.2% |
Small by default, complete when needed
This is a deliberately boring architecture: maintained libraries remain available, common apps stop paying for unused capabilities, and the user-facing build command stays compiler-free. More profiles can be added later from real import data without changing that contract.