Separate the single DEVELOPMENT.md into focused docs per audience: - cli/README.md — trim agent/interop sub-sections; user-facing contract, commands, data-dir, troubleshooting only. - cli/DEVELOPMENT.md — pared down to architecture, how-to-add-a-command, output conventions, testing, housekeeping. - cli/ROADMAP.md (new) — north-star, parity matrix, ordered milestones, non-goals. The live checklist for CLI feature parity. - cli/plans/2026-04-21-cli-distribution.md (new) — packaging strategy (Homebrew / winget / Scoop / deb / rpm / AUR / AppImage). - commons/plans/2026-04-21-event-renderer.md (new) — cross-cutting renderer design owned by commons, consumed by cli + desktop + android. Agentic routing: - .claude/skills/amy-expert/SKILL.md (new) — routing triggers + the five hard rules (thin-layer, JSON contract, non-interactive, data-dir-is-world, extract-before-adding). - references/command-template.md, extraction-recipe.md, output-conventions.md — bundled copy-paste references. Root .claude/CLAUDE.md: - Adds cli/ to the module list with its sharing rule. - Registers amy-expert in the skills table. - Documents per-module plans/ convention; freezes docs/plans/. https://claude.ai/code/session_01BQ5ZHwa8BAgEQ9zeM4CKhW
3.6 KiB
title, type, status, date, owner
| title | type | status | date | owner |
|---|---|---|---|---|
| feat(cli): native distribution across macOS / Windows / Linux | feat | proposed | 2026-04-21 | cli |
feat(cli): native distribution
Overview
Today amy ships only as ./gradlew :cli:run or a raw installDist
tree. Fine for dogfooding, not fine for the interop-test audience,
who need a single-binary install on every OS.
Goal: publish amy-<version>-<os>-<arch> artefacts on every GitHub
release, wrapped in the native package managers users already have.
Target matrix
| OS / channel | Strategy | Notes |
|---|---|---|
| macOS (arm64 + x64) | brew install amy-nostr |
Homebrew formula pointing at a tarball of installDist + a jlink'd JRE. Mirrors the existing amethyst-nostr cask. |
| Windows | winget install VitorPamplona.Amy + scoop install amy |
.zip with amy.bat launcher + jlink JRE. |
| Debian / Ubuntu | .deb via jpackage --type deb |
Depends on libc only; jlink JRE bundled. |
| Fedora / RHEL / openSUSE | .rpm via jpackage --type rpm |
Same. |
| Arch | AUR amy-nostr-bin |
Wrap the .tar.gz. |
| Any Linux | .tar.gz + AppImage |
AppImage for users without a package manager. |
| Nix / NixOS | nixpkgs entry |
Wrapper around installDist. |
| Zapstore | Extend zapstore.yaml |
Signed by the same Nostr key as the Android app. |
| GitHub Release | All of the above attached as assets | Use scripts/asset-name.sh for consistent naming. |
Shortest path to first release
- Extend the existing
desktopAppjpackageflow to also produce anamy-<version>-<os>-<arch>artefact. Reuse the signing and notarisation already configured for the desktop build. - CI matrix: macos-14 (arm64), macos-13 (x64), windows-latest,
ubuntu-latest. Each runner produces one tarball + one native
installer (
.dmg/.msi/.deb). - Publish as release assets; no package-manager submission yet.
- Only after the artefacts are stable (no path churn, no JRE incompatibilities): submit Homebrew formula, winget manifest, Scoop bucket, AUR PKGBUILD.
Why not GraalVM native-image
Tempting for startup time but loses FFI to secp256k1-kmp-jni-*,
which is how Quartz signs today. Revisit when Quartz ships a
pure-Kotlin fallback signer.
Auto-update
Out of scope for v1. Package managers handle it (brew upgrade,
winget upgrade, etc). Revisit if manual-install users complain.
Size budget
Target: < 80 MB installed with a jlink'd runtime. If we cross
that, audit transitive deps — Amy should not pull in Compose or
Android libs. Verify with ./gradlew :cli:installDist && du -sh cli/build/install/amy/ on CI and fail the build over a threshold.
Risks
- Code signing on macOS and Windows costs real money and requires secrets rotation. Reuse the desktop app's existing signing setup rather than standing up a separate keychain.
- Package-manager review latency. Homebrew / winget reviews can take days. Ship tarballs first; submissions later.
- JRE size. A jlink'd JDK 21 image is ~40 MB; adding OkHttp + Jackson + Quartz should land well under the 80 MB budget, but a bad transitive dep can double it overnight.
Open questions
- Single brew cask
amethyst-nostrwith anamyformula alongside, or a separateamy-nostrtap? Probably separate — different update cadence, different audience. - Should Amy ship in the same release as the desktop app, or on its own cadence? Leaning same release — shared CI, shared version — until the surfaces diverge.
Out of scope
- In-app auto-update UX (no CLI auto-update).
- macOS app notarization of the CLI (only signing). Notarization is
for bundled
.appGUIs.