Mosaic
Amalgame's web framework. A productive HTTPS server in the spirit of Next.js (filesystem routing), Phoenix (WebSocket channels), Caddy (automatic HTTPS via ACME). 100% Amalgame stack on top of OpenSSL 3.x and nghttp2 — not a toy IoT library.
Three-package architecture
Three composable packages, following the Amalgame convention (small, focused). You can import just TLS for a custom protocol, just HTTP for a low-level client/server, or Mosaic for the full stack.
amalgame-tls
OpenSSL 3.x binding (LibreSSL also supported). TLS 1.2/1.3, ALPN, SNI. ACME via certbot wrapper until the native pure-AM impl lands.
amalgame-net-http
Pure-AM HTTP/1.1 parser. HTTP/2 via nghttp2 (h2c + ALPN h2). RFC 6455 WebSocket. Parser limits (header timeout, body size, slowloris) for L7 anti-DDoS.
amalgame-web
Router (:param + *splat), WebContext, MemorySessionStore. Pure runtime library — the mosaic build tool lives in its own repo.
HTTPS Hello world — one ACME call, the binary handles the rest
namespace App import Amalgame.Web public class Program { public static void Main(string[] args) { WebApp.New() .Routes("./app") // Next.js-style filesystem routing .Static("/public", "./public") .WithSessions(SessionStore.JsonFile("./data/sessions")) .WithRateLimit(rps: 100, burst: 200) .WithCompression() // gzip + brotli .ListenAcme("my-site.com", "admin@my-site.com") // auto-HTTPS } }
Filesystem routing — Next.js convention
Every .am file under app/ becomes an endpoint. File names with [id] capture a parameter, [...slug] captures a catch-all. The router is generated automatically on every build.
my-app/ ├── amalgame.toml ├── mosaic.toml ├── app/ │ ├── index.am → GET / │ ├── about.am → GET /about │ ├── _middleware.am → middleware on app/ │ ├── _layout.am → HTML layout │ ├── users/ │ │ ├── index.am → GET /users │ │ ├── [id].am → GET /users/:id │ │ └── [id]/posts.am → GET /users/:id/posts │ └── api/ │ ├── login.am → POST /api/login │ └── [...path].am → catch-all route ├── lib/ ├── public/ └── data/
Each file exports Get / Post / Put / Patch / Delete functions. The HTTP verb is inferred from the name:
// app/users/[id].am namespace App.Users.Detail import Amalgame.Web public Function Get(req: HttpRequest, ctx: WebContext): HttpResponse { let id = ctx.Param("id") let user = Db.FindUser(id) if (user == null) { return HttpResponse.New().Status(404).Text("User not found") } return HttpResponse.New().Json(user) }
Three execution modes, one command each
DEV — hot reload
Filewatcher on app/ and lib/. Every change triggers an incremental recompile + browser livereload via WebSocket. Dev TLS optional, ACME disabled to avoid Let's Encrypt rate limits.
PROD modular — .so hot-swap
Mosaic binary + reloadable app.so. Shipping a patch = replace app.so + SIGHUP. Filewatcher disabled in prod for security.
PROD mono — single binary
Statically-linked binary named after your project. Static assets embedded. Ideal FROM scratch Docker, or zero-config VPS deploy.
L7 security built-in
L3/L4 defense stays with the operator (kernel sysctl, firewall, CDN). But everything application-layer is in the framework, opt-in via .With*():
- ✓WithSecurityHeaders — HSTS, X-Frame-Options=DENY, X-Content-Type-Options=nosniff, strict Referrer-Policy, basic CSP
- ✓WithCsrf — double-submit cookie + per-form token
- ✓WithCors — deny by default, explicit allow list
- ✓WithRateLimit — per-IP token bucket, configurable rps + burst
- ✓Slowloris protection — header timeout 10s, body timeout 30s, idle keep-alive 60s
- ✓Backpressure — when the worker queue is full, immediate 503 (never OOM)
- ✓Trusted-proxy allow-list —
X-Forwarded-Foronly trusted from whitelisted IPs - ✓Safe-by-default cookies:
Secure+HttpOnly+SameSite=Lax
Automatic HTTPS via ACME / Let's Encrypt
One ListenAcme(domain, email) call and Mosaic handles everything: bind :80 + :443, ACME v2 negotiation, in-process tls-alpn-01 challenge, cert caching, renewal 30 days before expiry. Multi-domain via SAN. Let's Encrypt staging opt-in via ACME_STAGING=1.
WebSocket with Phoenix-style pub/sub channels
WebSocket endpoints live on the same router as HTTP routes. The channel system is lightweight and single-process in v0.x (multi-node via Redis Pub/Sub planned for v1.x).
let chat: Channel = app.Channel("/chat") // a topic app.WebSocket("/chat", fn(ws, ctx) { chat.Subscribe(ws) // ws receives broadcasts while (ws.IsConnected()) { let msg = ws.RecvText() chat.Broadcast(msg) // sent to all subscribers } })
Concurrency: thread pool, not event loop
Simplified Go net/http model — one thread per active request, bounded worker pool, blocking I/O. No async/await (no "function colors" contaminating all your code). Multi-core native. The MPSC queue guarantees backpressure: if it fills up, immediate 503.
- ✓N workers default
2 × NumCpus, configurable viamosaic.toml - ✓Bounded queue at
N × 4— full = immediate 503 (no OOM) - ✓Built on
amalgame-threading(pthread + Win32, GC-safe) - ✓Graceful shutdown — acceptor stops, workers drain, clean exit
- ✓~100 KB per request — 256 active workers ≈ 25 MB for concurrency itself
Roadmap — 4 phases
The stack was assembled in two intensive days (2026-05-18 and 2026-05-19): nothing → HTTPS + HTTP/2 + WebSocket + filesystem routing + livereload, end-to-end. Here's what's left, in four phases:
Phase 1 — Production hardening (~2-3 weeks)
Blocking for any serious prod use. Security pack (CSRF/CORS/headers/rate-limit), ACME wrapper injection fix, CRLF/SSRF/open-redirect anti-injection, slowloris timeouts, concurrent worker pool, HTTP/1.1 keep-alive, IPv6 dual-stack, graceful SIGTERM shutdown.
Phase 2 — Real-world apps (~3-4 weeks)
amalgame-crypto (Argon2id, RSA, Ed25519, CSPRNG) → then auth basic + bearer + JWT + WebAuthn + TOTP. SQLite + Postgres DB bindings + migration framework. amalgame-template with auto-escape (closes the default-XSS hole). Typed validation. Multipart upload. JsonFileSessionStore and RedisSessionStore.
Phase 3 — UX + ops (~1-2 weeks)
Structured JSON/CLF access logs. Prometheus /metrics. OpenTelemetry tracing. /healthz + /readyz. systemd Type=notify. mosaic new <template> scaffold. dlopen hot-swap for reload without breaking WS. mosaic test integration harness.
Phase 4 — Polish + breadth (~2-3 weeks)
Pure-AM ACME (replaces certbot wrapper). DNS-01 challenges + wildcards via Cloudflare/Route53/OVH. mTLS client cert. OCSP stapling. Static file sendfile(2) + ETag + range. SSE. WebSocket fragmentation + subprotocols. amalgame-email SMTP. amalgame-queue background jobs. amalgame-cron. amalgame-openapi swagger gen.
Beyond HTTP — nginx-equivalent capabilities
Beyond HTTPS listening, Mosaic aims at the nginx/apache "front door" role: reverse proxy, load balancing, raw TCP/UDP proxying. Inventory planned in the beyond-http.md proposal.
HTTP/HTTPS reverse proxy
amalgame-net-proxy — proxy in front of N upstreams. HTTP/1.1 + HTTP/2 + transparent WebSocket forwarding. ~400 LoC for the base.
Load balancing
Round-robin, least-connections, IP-hash. Active health checks, outlier detection, sticky sessions via cookie hash. Part of amalgame-net-proxy v0.2.
Static file serving
Mosaic middleware, sendfile(2) zero-copy on Linux, range parsing, ETag, MIME DB, Cache-Control. ~300 LoC.
TCP/UDP raw proxy
amalgame-net-stream — nginx stream {} or HAProxy TCP mode equivalent. Fronting Postgres, Redis Sentinel, MQTT, UDP game servers. ~250 LoC.
SFTP via libssh2
amalgame-net-ssh — libssh2 binding. SFTP remains recommended for automation file transfer. ~500 LoC of glue.
SMTP relay
amalgame-net-smtp — receive + forward. Prod surface (DKIM, SPF, bounce, anti-spam) is massive; v0.1 targets basic relay, no antispam.
Follow the progress
Mosaic is public and in progress. The spec is the source of truth — phases advance through PRs tracked on the repos.