{"id":50102295,"url":"https://github.com/jdtoon/wachat","last_synced_at":"2026-05-23T08:04:55.438Z","repository":{"id":359723195,"uuid":"1247265028","full_name":"jdtoon/wachat","owner":"jdtoon","description":"Lean native desktop WhatsApp client in Go (Gio + whatsmeow). No Electron, no webview.","archived":false,"fork":false,"pushed_at":"2026-05-23T07:11:44.000Z","size":321,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T07:12:52.720Z","etag":null,"topics":["desktop","gio","go","low-memory","sqlite","whatsapp","whatsmeow"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdtoon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-23T05:02:15.000Z","updated_at":"2026-05-23T07:11:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jdtoon/wachat","commit_stats":null,"previous_names":["jdtoon/wachat"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/jdtoon/wachat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdtoon%2Fwachat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdtoon%2Fwachat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdtoon%2Fwachat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdtoon%2Fwachat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdtoon","download_url":"https://codeload.github.com/jdtoon/wachat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdtoon%2Fwachat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33387661,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["desktop","gio","go","low-memory","sqlite","whatsapp","whatsmeow"],"created_at":"2026-05-23T08:04:53.906Z","updated_at":"2026-05-23T08:04:55.397Z","avatar_url":"https://github.com/jdtoon.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# wachat\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![Go version](https://img.shields.io/github/go-mod/go-version/jdtoon/wachat)](./go.mod)\n[![Latest release](https://img.shields.io/github/v/release/jdtoon/wachat?display_name=tag\u0026sort=semver)](https://github.com/jdtoon/wachat/releases)\n[![Repo size](https://img.shields.io/github/repo-size/jdtoon/wachat)](https://github.com/jdtoon/wachat)\n[![Last commit](https://img.shields.io/github/last-commit/jdtoon/wachat/main)](https://github.com/jdtoon/wachat/commits/main)\n\nA lean, native desktop WhatsApp client written in Go. No Electron, no webview,\nno bundled browser. One process, low RAM, fast cold start.\n\n\u003e The official WhatsApp desktop client is Electron and eats hundreds of MB\n\u003e of RAM at rest. `wachat` aims to be the opposite: tens of MB at idle, sub-\n\u003e second cold start, and smooth scrolling over 100k-message histories.\n\n**Status:** early bootstrap. See [Status](#status).\n\n## North star\n\nPerformance first. Memory usage must be independent of history size, achieved\nby **virtualized rendering** (only visible rows laid out) and **keyset\npagination** (never `OFFSET`). If a harder approach is meaningfully faster or\nlighter, we take the harder approach.\n\n## Stack\n\n| Layer | Choice | Why |\n|------|--------|-----|\n| Language | Go | One lean runtime, protocol + UI in one process |\n| Protocol | [`whatsmeow`](https://pkg.go.dev/go.mau.fi/whatsmeow) | Mature multidevice library, compiled into the binary |\n| GUI | [`Gio`](https://gioui.org) | Immediate-mode, pure-Go, GPU-rendered, no webview |\n| Storage | [`modernc.org/sqlite`](https://pkg.go.dev/modernc.org/sqlite) | Pure-Go SQLite driver — no cgo, clean cross-compilation |\n| Media | Files on disk | Never blobs in the DB |\n\nSee [`CLAUDE.md`](./CLAUDE.md) for the full architecture and the non-negotiable\nconstraints (no Electron/webview, memory must be independent of history size,\nno DB blobs for media, no `OFFSET` pagination, etc.).\n\n## Build \u0026 run\n\nRequires **Go 1.25+** (pinned by `modernc.org/sqlite`). No CI pipeline — every\ngate runs locally.\n\n```bash\nmake hooks   # one-time: installs the local pre-commit hook\nmake check   # gofmt + go vet + go test ./...\nmake run     # go run .\nmake build   # produces stripped `wachat` binary\n```\n\nFirst run pairs with your phone via QR code displayed in the terminal\n(companion-device flow, same as WhatsApp Web). The session is persisted to\nSQLite — subsequent launches skip pairing.\n\n## Project layout\n\n```\nwachat/\n  main.go                   # Gio window + frame loop\n  internal/\n    wa/        client.go    # whatsmeow connect, pairing, events\n    store/     store.go     # SQLite: schema, dedup insert, keyset paging\n    ui/        app.go       # view-model state, two-pane layout\n               chatlist.go  # virtualized chat list\n               messages.go  # virtualized message view\n  scripts/                  # pre-commit hook + installer\n  Makefile\n```\n\n## Status\n\nTracks [`CLAUDE.md §12`](./CLAUDE.md#12-status--next-steps).\n\n- [x] `go.mod` + initial dependencies pinned (`modernc.org/sqlite`, `whatsmeow`, `gioui.org`)\n- [x] whatsmeow client wrapper (connect, QR pairing, session container)\n- [x] SQLite store: schema, insert-with-dedup, keyset page query\n- [x] Event handler → channel → notify pipeline (persist-first, non-blocking send)\n- [x] Gio frame loop + two-pane layout (chat list | messages)\n- [x] Virtualized chat list — bounded by viewport regardless of total\n- [x] Virtualized message view + bubble rendering (newest-at-bottom, grouping)\n- [x] whatsmeow connect + in-window QR pairing\n- [x] Auto-page older messages on scroll-near-end\n- [x] Send text end-to-end (composer + optimistic bubble)\n- [x] Full-text search across all history (SQLite FTS5)\n- [x] Jump-to-message from search hits (PageAround)\n- [x] Pairing state machine + connection banner + auto-reconnect\n- [x] Dark mode + density toggle + narrow-window collapse + persisted settings\n- [x] Lazy media cache + visibility tracker (see `internal/media`)\n- [x] Perf measurement harness — `make bench` (see Performance budget below)\n\n## Performance budget (validated as we go)\n\nTargets:\n\n- Idle RSS in the tens of MB (vs. hundreds for the official client)\n- Sub-second cold start on a warm OS file cache\n- No frame hitches scrolling a 100k-message chat\n\nMeasured via `make bench` at v0.1.0 (100k seeded messages, Intel Core\nUltra 7 258V, Windows 11, pure-Go build):\n\n| Metric                  | Result                        |\n|-------------------------|-------------------------------|\n| `store.Open`            | ~6 ms                         |\n| Go heap after 100k msgs | ~0.5 MB (**flat with N**)     |\n| Go runtime `Sys` (RSS≈) | ~16 MB                        |\n| First keyset page (50)  | ~1 ms                         |\n| Deep keyset page (90%)  | ~20 ms (cold index pages)     |\n| Bulk insert             | ~2.5k msgs/s (incl. FTS5)     |\n\nThe flat heap line is the load-bearing measurement — it proves the\n\"memory must be independent of history size\" constraint from\n[`CLAUDE.md §2`](./CLAUDE.md#2-non-negotiable-constraints). FTS5\nindexing on insert is the headline cost between v0.0.1 and v0.0.5\n(seed throughput dropped from ~10k msgs/s to ~2.5k); both numbers are\nfar above real-world inbound message rates.\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](./CONTRIBUTING.md). The TL;DR: run `make hooks` once,\nkeep `make check` green, never violate the guardrails in `CLAUDE.md §11`.\n\n## Risks \u0026 scope\n\n`wachat` uses a reverse-engineered library and violates WhatsApp's Terms of\nService; there is real account-ban risk. It is built for **personal use**.\nBulk-messaging or automation features are explicitly out of scope.\n\n## License\n\n[MIT](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdtoon%2Fwachat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdtoon%2Fwachat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdtoon%2Fwachat/lists"}