NoRaincheck/duck

LAN Forum

★ 0Forks 0PythonGitHub ↗Compare

README

Duck

A basic LAN messenger that is forum based.

It is laid out like 4chan:

  1. Board
  2. Thread
  3. Post (replies within a thread)

It is a host/client, supports SQLite persistence, and discovers peers via UDP multicast, gossiping events into a self-healing mesh. No accounts, no cloud — just a LAN.

How it works

Every Duck node is both a host and a client (inspired by wanwan):

  • Discovery — nodes announce themselves over UDP multicast (239.255.77.77:45454).
  • Relay — each node runs a TCP relay on a random free port.
  • Gossip — nodes connect to every peer, exchange events (boards, threads, posts), and deduplicate by event id, so the mesh converges on the same history and heals itself when nodes come and go.
  • Identity — a random node id is generated once and persisted, so a node is recognizably the same author across restarts. No accounts.
  • Persistence — all events and forum data live in a SQLite database.

Install

uv sync

Run

Serve the web UI (also exposes a JSON/SSE API):

uv run duck run --http 127.0.0.1:9080

Start another instance on a second machine (or the same one) and they discover each other within a few seconds. The same UI also runs in a browser on any machine on the LAN that can reach the HTTP port.

CLI

duck list                      # print the boards and their threads
duck create-board Dev --about "..."
duck post <board_id> "body" --title "title (optional)"
duck reply <thread_id> "body"
duck peers                     # discovered nodes

Flags: --name <display name>, --store <sqlite file> (default duck.db), --relay-port <p>, --iface <iface>, --peer host:port (manual peers), --wait <seconds> (dwell after an action so gossip can flush).

API

GET  /api/info                        node name, id, relay addr, version
GET/POST /api/boards
GET /api/boards/{id}/threads
GET /api/threads/{id}
GET /api/threads/{id}/posts
POST /api/threads                     {"board_id","body","title"} (title optional, defaults to first chars of body)
POST /api/posts                       {"thread_id","body"}
GET  /api/peers
GET  /api/events                      SSE stream of newly stored events

Tests

uv run pytest

Contributors

NoRaincheck

Issues