Wave Client for Emacs - Project Documentation
Table of Contents
- 1. Overview
- 2. Methodology
- 3. Technical Stack
- 4. Architecture
- 5. Testing
- 6. Progress Log
- 7. Issues & Resolutions
- 8. Build Times (FreeBSD 14.3)
- 9. Completed Milestones
- 10. Next Steps
- 11. References
- 12. Appendix: Beads Issue IDs
1. Overview
1.1. Project Goal
Emacs 24.1 released 2012-06-10, after Google Wave's service shutdown in April 2012 (dev ended 2010-08-04); the contemporary Emacs during Wave's active life (Sept 2009 - 2012) was the 23.x series (23.1 2009-07-29 through 23.4 2012-01-29), per gnu.org/software/emacs/history.html and Emacs version history. Corrected "was Emacs 24.x" to "was Emacs 23.x".
Revive and modernize the original 2009-era Google Wave Protocol Emacs client to work with modern infrastructure:
- Python 3.11+ (was Python 2.x era)
- Emacs 30.1 (was Emacs 23.x)
- FreeBSD 14.3 development environment
- FastAPI/WebSocket backend simulator
1.2. Repository
- Main: https://github.com/aygp-dr/wave-client-for-emacs
- Original Source Archive: https://github.com/aygp-dr/wave-client-elisp-original (private)
2. Methodology
2.1. Multi-Agent Workflow
Using Gas Town (gt) and Beads (bd) for coordinated AI-assisted development:
- Beads: AI-native issue tracking stored in
.beads/directory- Epics for major initiatives
- Tasks for discrete work items
- Dependencies between issues
- Priority levels (P0-P4)
- Gas Town: Multi-agent workspace manager
- Rigs for agent configuration
- Polecats for ephemeral workers
- Sling for work distribution
- Stash for handoffs
2.2. Development Approach
- Understand First: Read original elisp before modifications
- Simulator-First: Build Python server adhering to Wave Protocol
- Contract Testing: Verify protocol compliance between elisp and server
- Incremental Progress: Small, testable changes with git commits
3. Technical Stack
| Component | Version | Purpose |
|---|---|---|
| Python | 3.11.13 | Server backend |
| Emacs | 30.1 | Client runtime |
| FreeBSD | 14.3 | Development environment |
| FastAPI | latest | REST/WebSocket server |
| SQLite | 3.x | Wave data persistence |
| uv | 0.6.4 | Python package management |
| pytest | latest | Test framework |
| websockets | 15.0.1 | WebSocket client for tests |
| httpx | latest | HTTP client for tests |
4. Architecture
┌─────────────────────┐ ┌─────────────────────┐
│ Emacs Client │ │ Wave Server │
│ │ │ (Python/FastAPI) │
│ wave-mode.el │◄────────│ │
│ wave-list.el │ WS │ /ws endpoint │
│ wave-edit.el │ + │ /api/inbox │
│ wave-client.el │ HTTP │ /api/waves/{id} │
└─────────────────────┘ │ /health │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ SQLite Database │
│ wave_server.db │
└─────────────────────┘
Figure 1: Wave Client for Emacs – component architecture showing elisp modules, protocol layer, FastAPI server, and test suite
5. Testing
5.1. Test Results Summary (2026-01-10)
| Test Suite | Tests | Passed | Status |
|---|---|---|---|
| REST API Extended | 18 | 18 | ✓ Pass |
| WebSocket Extended | 14 | 14 | ✓ Pass |
| Total | 32 | 32 | ✓ Pass |
5.2. Running Tests
5.2.1. Python Integration Tests
# Start the server first
gmake server
# In another terminal, run tests
gmake test-python
# Or run specific test files
uv run pytest tests/integration/test_rest_extended.py -v
uv run pytest tests/integration/test_ws_extended.py -v
5.2.2. Quick API Smoke Test
gmake test-api
Output:
Testing Wave Server API...
=== Health Check ===
{"status":"healthy","timestamp":"2026-01-10T21:12:13.817809"}
=== Inbox ===
[{"id":"indexwave!indexwave","digest":"Wave Server Index","unread":0,"creator":"system@localhost"},...]
=== Root ===
{"message":"Wave Server API","status":"running","version":"0.2.0"}
5.3. Emacs Batch Mode Testing
Emacs batch mode allows headless testing without a GUI.
5.3.1. Available Make Targets
gmake elisp-version # Show Emacs version
gmake elisp-load-test # Test elisp modules load without errors
gmake elisp-check-syntax # Byte-compile check for warnings
gmake elisp-http-inbox # Fetch inbox via HTTP (requires server)
5.3.2. Emacs Version Check
gmake elisp-version
Output:
Emacs version: GNU Emacs 30.1 (build 1, aarch64-unknown-freebsd14.3)
5.3.3. Load Test (No Server Required)
Tests that all elisp modules load without errors:
gmake elisp-load-test
Output:
Testing elisp module loading... Loading wave-client.el... done Loading wave-mode.el... done Loading wave-list.el... done Loading wave-edit.el... done All modules loaded successfully!
5.3.4. HTTP Inbox Fetch (Requires Server)
# Start server first
gmake server &
sleep 3
# Fetch inbox via Emacs batch mode
gmake elisp-http-inbox
Output:
Fetching inbox via HTTP from localhost:9898... === INBOX (5 waves) === indexwave!indexwave: Wave Server Index localhost!conv+root: Discussion: Wave protocol features localhost!conv+root: Emacs client testing localhost!conv+root: Architecture discussion with diagram localhost!b+reply1: Charlie: Don't forget about the conflict resolution algorithms!
5.3.5. Batch Mode Elisp Code Example
The elisp-http-inbox target runs this code:
(require 'url)
(require 'json)
(defun fetch-inbox ()
(with-current-buffer
(url-retrieve-synchronously "http://localhost:9898/api/inbox" t)
(goto-char (point-min))
(re-search-forward "^$" nil t)
(let* ((json-object-type 'plist)
(inbox (json-read)))
(message "=== INBOX (%d waves) ===" (length inbox))
(dolist (wave (append inbox nil))
(message " %s: %s"
(plist-get wave :id)
(plist-get wave :digest))))))
(fetch-inbox)
5.4. WebSocket Testing
5.4.1. Python WebSocket Test Script
gmake ws-test
Uses scripts/ws-test.py to verify WebSocket connectivity:
Connecting to ws://localhost:9898/ws...
Connected!
Sending ProtocolOpenRequest for indexwave!indexwave
Received: {"version":0,"sequenceNumber":1,"messageType":"ProtocolWaveletUpdate",...}
All tests passed!
5.4.2. Interactive WebSocket Client
gmake ws-test-interactive
Opens an interactive session for manual WebSocket testing.
5.5. REST API Test Coverage
| Endpoint | Test Cases |
|---|---|
GET /health |
Returns 200, contains status, contains timestamp |
GET /api/inbox |
Returns list, items have required fields |
GET /api/waves/{id} |
404 for nonexistent, returns wavelet data |
POST /api/waves/{id}/submit |
Add participant, remove participant, returns version |
GET / |
Returns 200, contains version info |
| Error handling | Invalid JSON returns 422, missing fields returns 422 |
| Content types | All endpoints return application/json |
5.6. WebSocket Test Coverage
| Category | Test Cases |
|---|---|
| Connection lifecycle | Connect success, clean disconnect, multiple connections |
ProtocolOpenRequest |
Valid wave, nonexistent wave, multiple requests |
| Message handling | Malformed JSON, empty message, invalid type, missing fields |
| Sequence numbers | Response includes sequence, large sequence numbers |
| Concurrency | Rapid messages (10 in sequence), interleaved connections |
6. Progress Log
6.1. 2026-01-10: All Tests Passing
- Fixed
GET /api/waves/{id}500 error- Added
/healthendpoint towave_server.py - Fixed
doc_datatype handling (was list, expected dict)
- Added
- Updated REST tests to use correct
DeltaSubmissionschema - Updated WebSocket tests for
websockets15+ API - Final Results: 32/32 tests passing
6.2. 2026-01-10: Extended Test Suite Created
- Created
tests/integration/test_rest_extended.py(18 tests) - Created
tests/integration/test_ws_extended.py(14 tests)
6.3. 2026-01-08: WebSocket Tests Pass
- Completed
wave-client-for-emacs-x1z(WebSocket test task) - 8/8 WebSocket tests passing
- Database seeded with 4 waves, 5 wavelets, 3 updates
6.4. 2026-01-07: Elisp Batch Mode
- Added Makefile targets for headless testing
- Fixed batch mode async issues using
url-retrieve-synchronously
7. Issues & Resolutions
7.1. Resolved Issues
7.1.1. GET /api/waves/{id} Returns 500 [FIXED]
Problem: The waves endpoint had two issues:
- Missing
/healthendpoint doc_datawas sometimes a list instead of dict
Solution: Added type checking in get_wave endpoint:
if isinstance(doc_data, dict):
docs_dict[doc_id] = Document(
doc_id=doc_id,
contributors=doc_data.get("contributors", []),
...
)
else:
# doc_data is a primitive or list, wrap it as content
docs_dict[doc_id] = Document(
doc_id=doc_id,
contributors=[],
content=[doc_data] if not isinstance(doc_data, list) else doc_data
)
7.1.2. WebSocket Tests Failing with websockets 14+ [FIXED]
The new asyncio implementation (which removes the legacy ".open"/".closed" properties) became the default in websockets 14.0, not 15.0, per the project's official upgrade guide (websockets.readthedocs.io/en/stable/howto/upgrade.html: "The new asyncio implementation is the default since version 14.0... The open and closed properties are removed."). Corrected "15+"/"15.0+" to "14+"/"14.0+".
Problem: The websockets library 14.0+ removed the .open attribute.
Solution: Use .state instead:
from websockets.protocol import State
def is_connected(ws) -> bool:
return ws.state == State.OPEN
7.2. Known Limitations
7.2.1. Elisp Batch Mode Async
WebSocket operations in batch mode hit recursion limits due to
accept-process-output loop depth. Use synchronous HTTP for batch testing.
7.2.2. FreeBSD Wheel Building
uv rebuilds C extensions on FreeBSD. Workaround: use polecat worktree venv
which has pre-built packages.
8. Build Times (FreeBSD 14.3)
| Operation | Time |
|---|---|
uv sync (cold) |
2-5 min |
uv sync (warm) |
<1 sec |
pytest integration |
10-30 sec |
| elisp byte-compile | 5-10 sec |
| Server startup | 2-3 sec |
9. Completed Milestones
[X]FixGET /api/waves/{id}500 error[X]Run extended REST test suite (18/18 passing)[X]Run extended WebSocket test suite (14/14 passing)[X]Emacs batch mode testing working[X]Database seeding with test data
10. Next Steps
[ ]Implement TUI dashboard demo[ ]Full E2E elisp integration test[ ]Document protocol compliance[ ]Add GitHub Actions CI workflow
11. References
- Original Google Code Archive (downloads unavailable)
- Original Elisp Source Archive (private backup)
- Gas Town Introduction by Steve Yegge
- Beads + Gas Town Workflow (private gist)
12. Appendix: Beads Issue IDs
| ID | Type | Priority | Status | Description |
|---|---|---|---|---|
| wave-client-for-emacs-4ez | epic | P1 | active | Full Integration Test Suite |
| wave-client-for-emacs-75v | epic | P1 | active | TUI Dashboard Demo |
| wave-client-for-emacs-vjm | epic | P1 | active | Wave Protocol Simulator |
| wave-client-for-emacs-802 | task | P2 | completed | Seed database |
| wave-client-for-emacs-x1z | task | P2 | completed | WebSocket tests |
| hq-jxx | bug | P2 | open | Google Code Archive missing downloads |