This file provides guidance to AI coding agents when working with code in this repository.
XMTP push notification server in Go. Designed to be forked and customized per application. Receives messages from the XMTP network and delivers push notifications via APNS, FCM, or HTTP webhooks.
./dev/up # Start Docker services (PostgreSQL, XMTP node) — run once
./dev/build # Build binary to ./dist/
./dev/start # Run server with both API and listener enabled
./dev/run --api # Run API server only
./dev/run --help # Show all CLI optionsgo test -p 1 ./... # Unit tests (must run serially — shared database)
./dev/integration # Integration tests (Docker-based, TypeScript/Bun)Tests require ./dev/up to be running. The -p 1 flag is required because tests share a database instance that gets wiped between tests.
golangci-lint run --config dev/.golangci.yaml # Go linter
./dev/lint-shellcheck # Shell script linter./dev/gen-proto # Regenerate all proto code (requires buf CLI)
buf generate # Regenerate notification protos onlyThe server runs two optional components via flags:
- API server (
--api): Connect RPC over HTTP on port 8080. Handles device registration and topic subscriptions. Stateless, can scale horizontally. - XMTP listener (
--xmtp-listener): Persistent gRPC stream to XMTP node. Receives messages, looks up subscriptions, delivers notifications. Should be a single instance.
Both are started as goroutines from cmd/server/main.go and shut down gracefully on SIGINT/SIGTERM.
cmd/server/main.go— Entry point, wires up dependencies, starts servicespkg/api/— Connect RPC API server (registration, subscribe/unsubscribe endpoints)pkg/xmtp/— XMTP network listener with worker pool (default 50 workers, channel capacity 100)pkg/delivery/— Push notification delivery: APNS (apns.go), FCM (fcm.go), HTTP (http.go)pkg/installations/— Installation CRUD (device registration)pkg/subscriptions/— Subscription management (topic subscriptions with optional HMAC keys)pkg/interfaces/— Core interfaces (Installations,Subscriptions,Delivery) and domain typespkg/db/— SQLC queries, pgx/database/sql access, and golang-migrate migrations (seepkg/db/AGENTS.md)pkg/topics/— Topic parsing and message type detection (V3 MLS topics only)pkg/options/— CLI flag/env var configuration structspkg/proto/— Generated protobuf/Connect code (~28K LOC, do not edit)
- Dependency injection: Services receive interfaces via constructors;
main.gowires the object graph - Interface-driven: Core abstractions in
pkg/interfaces/; mocks generated viamockeryintomocks/ - Strategy pattern for delivery: Multiple
Deliveryimplementations; listener checksCanDeliver()then delegates - Soft deletes: Installations use
deleted_atfield - HMAC sender filtering: Prevents self-notifications using 30-day rolling keys
Options are parsed from CLI flags and environment variables (via go-flags struct tags). Local dev uses .env.local, Docker uses .env.docker.
PostgreSQL via database/sql + pgx, with sqlc query generation. Migrations live in pkg/db/migrations/. For DB-specific agent workflow, see pkg/db/AGENTS.md. Test DSN: postgres://postgres:xmtp@localhost:25432/postgres?sslmode=disable.
- Unit tests use mockery-generated mocks for interface boundaries
- API tests start a real HTTP server with mocked services
test/helpers.goprovides isolated per-test PostgreSQL databases viaCreateTestDb()- Integration tests run full stack in Docker with HTTP delivery for verification