Free-threading-native QUIC and HTTP/3 for Python 3.14t — sans-I/O, typed
Project description
⟢⟣ Zoomies
Free-threading-native QUIC and HTTP/3 for Python 3.14t — sans-I/O, typed
Using zoomies from an AI agent (or moving fast)? See CLAUDE.md for a concise library-user guide: mental model, timing contract, event cheatsheet, and foot-guns.
import time
from zoomies.core import QuicConnection, QuicConfiguration
from zoomies.events import HandshakeComplete
config = QuicConfiguration(certificate=cert, private_key=key)
conn = QuicConnection(config)
# Sans-I/O: feed datagrams in, get events out
now = time.monotonic()
events = conn.datagram_received(datagram, addr, now=now)
for event in events:
if isinstance(event, HandshakeComplete):
...
for dg in conn.send_datagrams(now=now):
sock.sendto(dg, addr)
What is Zoomies?
Zoomies is a sans-I/O protocol library for QUIC (RFC 9000) and HTTP/3 (RFC 9114). Native to the b-stack (Pounce, Chirp), it has no b-stack dependencies and works anywhere — pure Python, cryptography only, free-threaded Python 3.14t. Alpha: full TLS 1.3 handshake, 1-RTT packets, loss recovery (RFC 9002), and congestion control.
What's good about it:
- Sans-I/O — Protocol layer consumes bytes, produces bytes. No socket access. Caller owns I/O.
- Types as contracts — Frozen dataclasses for events, Protocols for handlers.
- Free-threading native — No C extensions with limited API. Uses cryptography (3.14t-compatible).
- Composition — Packet → Crypto → Stream → Connection → Recovery → HTTP/3. Each layer testable in isolation.
- Loss recovery — RFC 9002 loss detection, RTT estimation, NewReno congestion control. Built into the connection layer.
What it does
| API | Description |
|---|---|
QuicConnection.datagram_received(data, addr, now=) |
Feed UDP datagram in, get protocol events |
QuicConnection.send_datagrams(now=) |
Get outbound datagrams to transmit |
QuicConnection.send_stream_data(stream_id, data, end_stream) |
Queue application data on a QUIC stream |
QuicConnection.get_timer() |
Next deadline for handle_timer() (see Timer Integration) |
QuicConnection.handle_timer(now) |
Process timer expiry (idle timeout, PTO retransmission) |
QuicConnection.connect() |
Client: generate Initial packet with ClientHello |
QuicConnection.close() |
Send CONNECTION_CLOSE and shut down |
H3Connection.handle_event(event) |
Process QUIC events into HTTP/3 events |
encode_headers / decode_headers |
QPACK header compression |
pull_quic_header() |
Parse QUIC packet headers (Initial, Handshake, etc.) |
zoomies.recovery |
Loss detection, RTT estimation, congestion control (RFC 9002) |
Key events: HandshakeComplete, StreamDataReceived, ConnectionClosed, NewSessionTicket, ZeroRttAccepted, ZeroRttRejected, PacketDropped, DecryptionFailed
Installation
pip install zoomies
Requires Python 3.14+
Quick Start
QPACK encode/decode
from zoomies.h3 import Header, decode_headers, encode_headers
headers = [
Header(name=":method", value="GET"),
Header(name=":path", value="/api/users"),
Header(name=":scheme", value="https"),
]
encoded = encode_headers(headers)
decoded = decode_headers(encoded)
Parse QUIC Initial packet
from zoomies.encoding import Buffer
from zoomies.packet import pull_quic_header
buf = Buffer(data=raw_bytes)
header = pull_quic_header(buf, host_cid_length=None)
print(f"Version: {header.version:#x}, CID: {header.destination_cid}")
Sans-I/O connection (server)
import time
from zoomies.core import QuicConnection, QuicConfiguration
from zoomies.events import HandshakeComplete
with open("cert.pem", "rb") as f:
cert = f.read()
with open("key.pem", "rb") as f:
key = f.read()
config = QuicConfiguration(certificate=cert, private_key=key)
conn = QuicConnection(config)
now = time.monotonic()
events = conn.datagram_received(datagram, addr, now=now)
for event in events:
if isinstance(event, HandshakeComplete):
print("Handshake done!")
for dg in conn.send_datagrams(now=now):
sock.sendto(dg, addr)
Sans-I/O connection (client)
import time
from zoomies.core import QuicConnection, QuicConfiguration
config = QuicConfiguration(is_client=True, verify_mode=False) # test only — use ca_certs in production
conn = QuicConnection(config)
conn.connect()
now = time.monotonic()
for dg in conn.send_datagrams(now=now):
sock.sendto(dg, server_addr)
Timer integration (required for production use)
Zoomies is sans-I/O: the library never sleeps. You must drive the timer by polling
get_timer() and calling handle_timer() when the deadline passes. Without this,
idle timeouts and PTO retransmissions won't fire.
import time
while True:
now = time.monotonic()
# 1. Process incoming datagrams
for dg in receive_from_socket():
events = conn.datagram_received(dg, addr, now=now)
handle_events(events)
# 2. Send outbound datagrams
for dg in conn.send_datagrams(now=now):
sock.sendto(dg, addr)
# 3. Drive the timer — this is what makes idle_timeout and PTO work
deadline = conn.get_timer()
if deadline is not None and now >= deadline:
events = conn.handle_timer(now)
handle_events(events)
See examples/realistic_server.py for a complete select()-based implementation.
0-RTT early data (TLS resumption)
After a first connection, capture the session ticket and reuse it to send data before the handshake completes on reconnection:
from zoomies.events import NewSessionTicket, ZeroRttAccepted, ZeroRttRejected
# 1. First connection: capture the session ticket
for event in events:
if isinstance(event, NewSessionTicket):
stored_ticket = event.ticket # save externally (file, DB, etc.)
# 2. Reconnect with the ticket
config = QuicConfiguration(is_client=True, session_ticket=stored_ticket, ...)
conn = QuicConnection(config)
conn.connect()
# 3. Queue data immediately (sent as 0-RTT before handshake completes)
conn.send_stream_data(stream_id=0, data=b"early request", end_stream=True)
# 4. Check if the server accepted 0-RTT
for event in events:
if isinstance(event, ZeroRttAccepted):
pass # early data was accepted
elif isinstance(event, ZeroRttRejected):
pass # resend data — it will go as 1-RTT after handshake
See examples/zero_rtt_resumption.py for the full end-to-end flow.
Run the examples (from repo root):
uv run python -m examples.qpack_roundtrip
uv run python -m examples.parse_initial_packet
uv run python -m examples.sans_io_connection
uv run python -m examples.client_server
Examples
| Example | Description |
|---|---|
examples/qpack_roundtrip.py |
QPACK header encode/decode |
examples/parse_initial_packet.py |
Parse QUIC Initial packet header |
examples/sans_io_connection.py |
Sans-I/O QuicConnection demo (uses test fixtures) |
examples/stream_echo.py |
Stream reassembly, RTT estimation, congestion control, loss detection, PTO timer loop |
examples/client_server.py |
HTTP/3 GET request/response over loopback (client + server in one process) |
Usage
Events — Frozen dataclasses for protocol state changes
from zoomies.events import (
HandshakeComplete,
StreamDataReceived,
StreamReset,
ConnectionClosed,
)
for event in conn.datagram_received(datagram, addr):
match event:
case HandshakeComplete():
...
case StreamDataReceived(stream_id=sid, data=data):
...
case StreamReset(stream_id=sid, error_code=code):
...
case ConnectionClosed():
...
HTTP/3 — H3Connection for request/response
from zoomies.h3 import H3Connection
from zoomies.events import H3HeadersReceived, H3DataReceived
# Wrap a QuicConnection to add HTTP/3 framing
h3 = H3Connection(sender=quic_conn)
# Client: send request
h3.send_headers(stream_id=0, headers=[
(b":method", b"GET"), (b":path", b"/"),
(b":scheme", b"https"), (b":authority", b"localhost"),
], end_stream=True)
# Server: process QUIC events through H3
for quic_event in events:
for h3_event in h3.handle_event(quic_event):
match h3_event:
case H3HeadersReceived(headers=hdrs):
...
case H3DataReceived(data=body):
...
Free-threading — Python 3.14t
Zoomies uses frozen dataclasses, no shared mutable state, and cryptography (3.14t-compatible). Safe to run multiple QuicConnection instances from different threads.
Development
git clone https://github.com/lbliii/zoomies.git
cd zoomies
uv sync --group dev
pytest
Lint and types:
ruff check src tests
ty check
Related: The Bengal Ecosystem
Zoomies is developed as part of the b-stack but is standalone. No imports from Bengal, Chirp, or Pounce. A structured reactive stack — every layer written in pure Python for 3.14t free-threading.
| ᓚᘏᗢ | Bengal | Static site generator | Docs |
| ∿∿ | Purr | Content runtime | — |
| ⌁⌁ | Chirp | Web framework | Docs |
| =^..^= | Pounce | ASGI server | Docs |
| )彡 | Kida | Template engine | Docs |
| ฅᨐฅ | Patitas | Markdown parser | Docs |
| ⌾⌾⌾ | Rosettes | Syntax highlighter | Docs |
| ⟢⟣ | Zoomies | QUIC/HTTP/3 ← You are here | — |
Python-native. Free-threading ready. No npm required.
License
MIT License — see LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bengal_zoomies-0.3.3.tar.gz.
File metadata
- Download URL: bengal_zoomies-0.3.3.tar.gz
- Upload date:
- Size: 133.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ba3184c0fa99bf6da4a1a38de3216054f98f5a79ecb4acd3c254d41d9804c48
|
|
| MD5 |
9c1001a2de324516ac81dc9b101ef6f7
|
|
| BLAKE2b-256 |
957309f126ee92e1ba9a193c1309f5df01ce3156ce7a8d75a3e385fefeb1e76f
|
Provenance
The following attestation bundles were made for bengal_zoomies-0.3.3.tar.gz:
Publisher:
python-publish.yml on lbliii/zoomies
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bengal_zoomies-0.3.3.tar.gz -
Subject digest:
7ba3184c0fa99bf6da4a1a38de3216054f98f5a79ecb4acd3c254d41d9804c48 - Sigstore transparency entry: 1351467781
- Sigstore integration time:
-
Permalink:
lbliii/zoomies@43b28faca36377a0cd5250a13bcf4eac204a8514 -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/lbliii
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@43b28faca36377a0cd5250a13bcf4eac204a8514 -
Trigger Event:
release
-
Statement type:
File details
Details for the file bengal_zoomies-0.3.3-py3-none-any.whl.
File metadata
- Download URL: bengal_zoomies-0.3.3-py3-none-any.whl
- Upload date:
- Size: 85.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e99849ec8ef4d0e86461213619a2705b588ac3f5946b880e9e6ae2c1ab9b6e91
|
|
| MD5 |
9aaaca611eadee63298c29ce8080bc4f
|
|
| BLAKE2b-256 |
297d431f386febf15c0182bd65d71ab873c7f982d6293bdf49ce5afcc7ed5070
|
Provenance
The following attestation bundles were made for bengal_zoomies-0.3.3-py3-none-any.whl:
Publisher:
python-publish.yml on lbliii/zoomies
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bengal_zoomies-0.3.3-py3-none-any.whl -
Subject digest:
e99849ec8ef4d0e86461213619a2705b588ac3f5946b880e9e6ae2c1ab9b6e91 - Sigstore transparency entry: 1351467817
- Sigstore integration time:
-
Permalink:
lbliii/zoomies@43b28faca36377a0cd5250a13bcf4eac204a8514 -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/lbliii
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@43b28faca36377a0cd5250a13bcf4eac204a8514 -
Trigger Event:
release
-
Statement type: