跪拜 Guibai
← All articles
Backend · GitHub

Kotae: The 12.7 MB Postman Alternative That Skips Electron and the Cloud

By 小Z先生 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

A 12.7 MB installer and no Chromium bundle is enough for a full API client; the pattern of Go owning network I/O and the system webview rendering is directly reusable. The signature-diff SQLite save and the honest no-sandbox trust toggle are the two decisions most worth copying.

Summary

Kotae replaces Postman's collaboration stack with a single machine: no account, no cloud, no backend. The Go-powered desktop shell (via the MyGo framework) drives a system WebView (WebView2 on Windows) running a standard Vite/TypeScript frontend, so the executable is 12.7 MB and the installer 4.8 MB. Go owns every network primitive, bypassing CORS, unlocking arbitrary headers and Set-Cookie visibility, and sharing a cookie jar with WebSocket handshakes. Business logic lives entirely in a 2,800-line store.ts; Go exposes only platform capabilities.

Storage moved from a whole-file JSON workspace to SQLite, with a save() routine that fingerprints each row and only issues INSERT/UPDATE/DELETE statements for changed rows, all in a single transaction. Scripts run via AsyncFunction directly in the page, no sandbox: imported scripts from Postman Collection or HAR are marked 'untrusted' and only execute after an explicit trust toggle. A design system is enforced by a lint script that fails on bare hex colors, raw font-size values, unregistered animations, and undefined CSS variables. Two WebView2 performance issues are documented, including a cold GPU cache that caused a 74ms first-frame stutter, fixed by pre-warming widget rendering after startup.

Testing runs 105 end-to-end cases against the real binary, real windows, real Go HTTP, with no Playwright/Cypress. The test harness uses an Automation plugin built only under //go:build e2e, drives a Unix socket, and each run uses a fresh app name and temp userData to stay isolated. Explicit non-goals: no collection runner, no load testing, no cloud sync, no OpenAPI generation.

Takeaways
— The Windows executable is 12.7 MB; the NSIS installer is 4.8 MB; the frontend Vite build is 325 KB and embedded in the binary.
— Go sends every HTTP request, eliminating the four browser limitations: CORS, restricted headers, invisible Set-Cookie, and browser-owned cookies.
— Per-request options like proxy and TLS-skip are smuggled into a shared http.Client via internal X-Mygo- headers stripped in a custom RoundTrip.
— Request trace data (DNS, connect, TLS, first byte) is captured via httptrace per hop and returned as base64 JSON in X-Mygo-Trace.
— WebSocket handshakes and frames are handled in Go with the same http.Client, so cookies from prior logins carry over automatically.
— SSE stays in the frontend as a plain HTTP response stream; no separate Go channel is needed.
— Storage uses SQLite with row signatures; save() only runs INSERT/UPDATE/DELETE for changed rows, all in one transaction, with deleted rows removed by diff.
— A 220ms debounce batches continuous edits.
— Scripts run via AsyncFunction with no sandbox; imported scripts are 'untrusted' until the user clicks trust.
— Script execution gets a 5-second budget, but network wait time doesn't count against it.
— On 401, a post-script can call pm.execution.resend() to re-send the same request up to 3 times after refreshing the token.
— UI tokens are enforced by scripts/check-ui-tokens.mjs which exits non-zero on bare hex, rgb, hsl, raw font-size, border-radius, box-shadow, undefined var(), and unregistered animation timings.
— A cold WebView2 GPU cache caused a 74ms first-frame stutter on first script creation; pre-warming with two frames of opacity:0.01 content fixed it.
— Removing backdrop-filter from modal overlays eliminated a slideshow on software-rendered machines.
— End-to-end tests run 105 cases against the real binary, real windows, and real Go HTTP, without Playwright/Cypress; e2e automation is built only under //go:build e2e.
Conclusions

The two WebView2 performance fixes apply to any webview-based desktop app: cold GPU shader compilation can dominate first render, and backdrop-filter is often not worth its cost in software rendering.

The decision to skip a sandbox for scripts is refreshingly honest. Rather than building a fake isolation layer, the tool marks imported scripts as untrusted and forces a conscious click. This is a workable model for a single-user local tool, though it wouldn't fit a multitenant service.

Keeping business logic in a 2,800-line TypeScript file while Go stays a thin platform layer pays off: UI, request sending, and storage changes never touched the same file. That boundary is worth copying.

The diff-based SQLite save() is a clean way to avoid write amplification; the critical detail is excluding timestamps from the signature, otherwise every edit rewrites the whole database.

Concepts & terms
MyGo
A Go desktop application framework that uses the system's native webview instead of bundling Chromium. It handles packaging, installers, auto-update, tray, and single-instance behavior, letting developers build a desktop app with a plain Vite/TypeScript frontend.
System WebView
The OS-provided web rendering engine (WebView2 on Windows, WKWebView on macOS). Using it instead of bundling Chromium eliminates the ~100 MB runtime that Electron ships, at the cost of behavior and version being controlled by the OS.
purego
A Go library for loading native shared libraries without cgo. In Kotae it lets the sqlite plugin use a precompiled sqlite3 DLL (or .dylib) with no external database install.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗