Problem
The micasa binary is ~54 MB stripped (go build -ldflags="-w -s" -trimpath ./cmd/micasa). That's heavy for an interactive TUI and bloats download archives and container layers.
On-disk breakdown (53.5 MB)
| Section |
Size |
Notes |
.text (machine code) |
~22 MB |
|
.gopclntab (PC→line tables) |
~18 MB |
needed for stack traces; scales ~linearly with code |
.rodata (strings, embedded data, type info) |
~12 MB |
|
.data / .noptrdata / .typelink / .itablink |
~2 MB |
|
.bss |
(33 MB) |
not on disk — the crypto/internal/fips140/drbg.memory 32 MiB scratch buffer, runtime-only |
Biggest discretionary contributors
- Multi-provider LLM stack —
internal/llm/client.go unconditionally imports 10 any-llm-go providers. The gemini provider drags in google.golang.org/genai → google.golang.org/grpc + google.golang.org/protobuf + cloud.google.com/go/auth (s2a-go, gax-go, …). anthropics/anthropic-sdk-go (~1.4 MB) and openai-go (~1.8 MB, shared by openai/groq/mistral/deepseek/llamacpp/llamafile) are also linked. Rough total incl. proportional gopclntab/rodata: ~12–16 MB.
alecthomas/chroma/v2 lexers via glamour markdown rendering — code + dozens of embedded language lexers. ~2–4 MB.
itchyny/gojq via internal/config/query.go (config query <jq> feature) — full jq engine + yacc parser tables. ~1.5 MB.
brianvoe/gofakeit/v7 via internal/fake (demo data) — code + embedded word lists. ~1.5 MB.
Quick wins already identified
.goreleaser.yaml ldflags only sets -X main.version=… — no -s -w, so released archives aren't even stripped (~3–5 MB larger than they need to be).
upx --best --lzma takes the stripped binary 53.5 MB → 12.5 MB (measured). Tradeoffs: small one-time decompress on launch, breaks go version -m, occasional Windows AV false positives, friction with macOS code-signing/notarization.
Options to weigh
- A. Add
-s -w to goreleaser ldflags (trivial, no downside).
- B. Add a UPX post-build hook in goreleaser (4× smaller downloads; band-aid — same runtime memory + container size; macOS may need exclusion or post-pack signing).
- C. Collapse / replace the
any-llm-go multi-provider stack with thin direct HTTP clients (OpenAI-compatible chat-completions + Anthropic Messages cover everything micasa does — NL→SQL and summary calls). Real fix, ~10–15 MB, breaking refactor of internal/llm. Aligns with "LLM is opt-in, not a crutch."
- C1 (lighter). Just drop the
gemini provider import to shed genai/grpc/protobuf/cloud-auth (~6–10 MB), keep the rest.
- D. Drop
gojq from config querying (replace with a path selector or just config show) — ~1.5 MB.
- E. Trim
chroma lexers down to the few languages actually highlighted — needs a fork/vendored registry; brittle across chroma upgrades. ~2–3 MB.
Recommendation
Do A + B now for shipped artifacts (≈ 57 MB unstripped release → ≈ 12 MB), then C/C1 as a follow-up to cut the uncompressed footprint (UPX-decompressed memory and container layers still carry the full size).
Problem
The
micasabinary is ~54 MB stripped (go build -ldflags="-w -s" -trimpath ./cmd/micasa). That's heavy for an interactive TUI and bloats download archives and container layers.On-disk breakdown (53.5 MB)
.text(machine code).gopclntab(PC→line tables).rodata(strings, embedded data, type info).data/.noptrdata/.typelink/.itablink.bsscrypto/internal/fips140/drbg.memory32 MiB scratch buffer, runtime-onlyBiggest discretionary contributors
internal/llm/client.gounconditionally imports 10any-llm-goproviders. Thegeminiprovider drags ingoogle.golang.org/genai→google.golang.org/grpc+google.golang.org/protobuf+cloud.google.com/go/auth(s2a-go, gax-go, …).anthropics/anthropic-sdk-go(~1.4 MB) andopenai-go(~1.8 MB, shared by openai/groq/mistral/deepseek/llamacpp/llamafile) are also linked. Rough total incl. proportional gopclntab/rodata: ~12–16 MB.alecthomas/chroma/v2lexers viaglamourmarkdown rendering — code + dozens of embedded language lexers. ~2–4 MB.itchyny/gojqviainternal/config/query.go(config query <jq>feature) — full jq engine + yacc parser tables. ~1.5 MB.brianvoe/gofakeit/v7viainternal/fake(demo data) — code + embedded word lists. ~1.5 MB.Quick wins already identified
.goreleaser.yamlldflagsonly sets-X main.version=…— no-s -w, so released archives aren't even stripped (~3–5 MB larger than they need to be).upx --best --lzmatakes the stripped binary 53.5 MB → 12.5 MB (measured). Tradeoffs: small one-time decompress on launch, breaksgo version -m, occasional Windows AV false positives, friction with macOS code-signing/notarization.Options to weigh
-s -wto goreleaser ldflags (trivial, no downside).any-llm-gomulti-provider stack with thin direct HTTP clients (OpenAI-compatible chat-completions + Anthropic Messages cover everything micasa does — NL→SQL and summary calls). Real fix, ~10–15 MB, breaking refactor ofinternal/llm. Aligns with "LLM is opt-in, not a crutch."geminiprovider import to shed genai/grpc/protobuf/cloud-auth (~6–10 MB), keep the rest.gojqfrom config querying (replace with a path selector or justconfig show) — ~1.5 MB.chromalexers down to the few languages actually highlighted — needs a fork/vendored registry; brittle across chroma upgrades. ~2–3 MB.Recommendation
Do A + B now for shipped artifacts (≈ 57 MB unstripped release → ≈ 12 MB), then C/C1 as a follow-up to cut the uncompressed footprint (UPX-decompressed memory and container layers still carry the full size).