guppy-protocol 0.1.1

An implementation of the Guppy protocol v0.4.4 (guppy://): async UDP client and server with chunking, acknowledgement, and retransmission, plus a CLI. The smolweb-over-UDP protocol.
Documentation
# guppy-protocol

> **Home:** [`mark-ik/serval`]https://github.com/mark-ik/serval, at
> `components/errand/protocols/guppy-protocol` (adopted 2026-07). The former standalone repository is archived
> and links here.


A Rust implementation of the
[Guppy protocol](https://github.com/dimkr/guppy-protocol) v0.4.4
(`guppy://`): an async UDP client and server with chunking, per-packet
acknowledgement, windowed transmission, and retransmission, plus a small CLI.

Guppy is dimkr's smolweb-over-UDP protocol, inspired by TFTP, DNS, and
Spartan, designed to be servable from a microcontroller over a single UDP
socket (default port 6775). A request is one datagram carrying a URL; the
response is a numbered packet sequence the client acknowledges packet by
packet, ended by an empty end-of-file packet. User input rides the URL query,
prompted by a `1 <prompt>` packet; `3` redirects and `4` errors are
single-packet answers.

This crate is independent and unaffiliated with the protocol's author. The
crates.io name is qualified (`guppy-protocol`) because the bare `guppy` name
is used by an unrelated project.

## Library

```rust
use guppy_protocol::{GuppyResponse, fetch, FetchOptions};

match fetch("guppy://guppy.mozz.us/", &FetchOptions::default()).await? {
    GuppyResponse::Success { mime, body } => { /* render */ }
    GuppyResponse::Prompt { text } => { /* re-request with ?input */ }
    GuppyResponse::Redirect { target } => { /* user-confirmed re-request */ }
    GuppyResponse::Error { message } => { /* show it; errors are for users */ }
}
```

Serving is a `Handler` (any async closure) returning the same
`GuppyResponse`; the server owns chunking, the send window, retransmission,
session tracking, and duplicate-request suppression. `FileHandler` is the
built-in static-directory handler.

## CLI

```sh
cargo install guppy-protocol --features cli

guppy fetch guppy://guppy.mozz.us/
guppy serve --root ./site --listen 0.0.0.0:6775
```

## Spec coverage (v0.4.4)

| Spec point | State |
| --- | --- |
| Request = one datagram `url\r\n`, ≤ 2048 bytes | enforced both sides |
| Success / continuation / EOF packet forms, seq +1, random start in [6, 2³¹−1] | full; the "don't confuse seq 39/41 with 3/4" disambiguation is unit-tested |
| Per-packet acknowledgement; duplicate packets re-acked; duplicate acks ignored | client + server |
| Retransmission (request, acks, unacked response packets) | both sides, tunable intervals |
| Out-of-order transmission | server sends a configurable window ahead of acks; client caches and re-orders (tested against scrambled + duplicated delivery) |
| Sessions (source-addr keyed, duplicate requests ignored, timeout, DoS cap) | server, with a post-completion linger |
| Input prompts (`1`), redirects (`3`), errors (`4`) | full round trip; input decodes from the URL query |
| Chunk size ≥ 512 recommendation | default 512, configurable |
| One source port per session | client binds a fresh socket per fetch |

Not covered: encryption (the spec declares it out of scope).

## License

MIT. The specification declares no license; this implementation is original
code.