- Rust 67.7%
- TypeScript 17.3%
- D 5.6%
- CSS 3.2%
- Shell 2.9%
- Other 3.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
ci / check (push) Successful in 11m1s
ci / desktop (push) Successful in 18m12s
ci / e2e (push) Successful in 39m42s
packaging / arch (push) Successful in 16m22s
web-image / web-image (push) Successful in 18m56s
packaging / debian (push) Successful in 24m21s
packaging / fedora (push) Successful in 30m26s
packaging / nix (push) Successful in 18m47s
packaging / release (push) Successful in 1m49s
|
||
| .forgejo/workflows | ||
| app | ||
| ci | ||
| crates | ||
| devserver | ||
| docs | ||
| e2e | ||
| lyskom-elisp-client@99b646108e | ||
| lyskom-server@510601bb38 | ||
| packaging | ||
| tools | ||
| .dockerignore | ||
| .gitignore | ||
| .gitmodules | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| clippy.toml | ||
| deny.toml | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| README.md | ||
NeoKOM
A modern LysKOM client for desktop and browser, aimed at kom.lysator.liu.se. One Rust codebase: native on the desktop, WebAssembly in the browser.
Status: in daily use for reading and writing by ordinary (non-admin) users; the latest release is on the releases page. What comes next is in docs/ROADMAP.md, and work is tracked in the issues. The Emacs client and jskom are the yardsticks.
Use it
- In the browser: https://neokom.lysator.liu.se. On a phone, add it to the home screen and it runs as an app.
- On the desktop: packages for Arch, Debian, Fedora and NixOS (below).
- On your own network: one Docker container with the web app and its relay, see docs/DOCKER.md.
What it does
Reading
- Exact unread counts per channel, and a list of all your channels.
- Two reading orders, a setting:
- a thread at a time: the next unread post brings its whole thread, and the thread's unread posts are read top to bottom;
- the Emacs order: footnotes, then comments depth-first, then the next channel by priority. Chronological reading is an option there.
- Threads are shown whole, with replies indented, branches collapsible and unread posts marked. Posts you scroll past count as read.
- Space or Enter does the next thing (read next, next channel). Review a post by number, the post it replies to, or a whole reply tree; skip a tree; save posts and list them under "Sparade inlägg".
- A channel's posts can be scrolled back through like a chat, however many there are: only what is near the screen is kept in memory.
- Unread FAQs come first when you enter a channel, remembered on the server the way the Emacs client does it.
Conversations
- Direct messages are shown as chats, grouped by the person you talk to.
- Reactions: an emoji is written as a fast reply, and identical ones are counted ("👍 3"). The Emacs client shows an ordinary fast reply.
- Mentions:
@suggests people, and posts that mention you are listed. - Notifications for messages, replies to you and mentions, with quiet hours. Desktop notifications on the desktop; in the browser while the tab is open.
People and channels
- Browse all channels by activity, members or name, and join with one tap.
- Profiles with the presentation, recent posts and memberships. Avatars are the first picture in a presentation, otherwise coloured initials. Edit your own presentation, picture and name.
- Who is logged in, with presence dots and what-am-I-doing next to names.
- Mute a thread, a person or a subject; follow a thread.
- Search: people and channels by name on the server, and the posts you have read (subjects and text) from a local index, since lyskomd has no full-text search.
- Sign up from the login page.
Writing
- New posts, replies, footnotes and private replies. Recipients follow Protocol A's rules; the composer advises (author not a member, redirects, no-comments) without overruling you.
- A toolbar for pictures, bold, italic and quotes, writing the plain-text
conventions every client reads (*bold*, /italic/,
>quotes). Quote a selection when replying. - Pictures: pick, paste or drop one, and it is scaled to fit the server's text limit.
- Drafts are saved as you write and offered back after a crash or a reconnect.
- Requests to readers (no comments, private replies, read confirmation, readable without login), cross-references and fast replies.
- Lines are wrapped at 72 characters. Text is sent as Latin-1 when it fits, otherwise UTF-8.
Content
- Plain text, decoded by its charset, then UTF-8, then Latin-1; old 7-bit
Swedish (
{|}for äöå) converted on request. Links are clickable. - Pictures, multipart posts with attachments, HTML and MHTML pages. HTML is rendered from an allow-list, and external images are blocked until you open them. SVG is never rendered.
- Aux items in the post: imported mail and feed items with their original author and date, attachments, fast replies, cross-references, read confirmations, requests to readers, FAQ links and alternate names. A table of every aux item is one click away.
Everything else
- Phone layout with a bottom tab bar, and swipe for the next post.
- Stays connected: after sleep or a network change it reconnects, logs in again and keeps your place.
- Stay logged in: the password goes in the system keyring on the desktop and in the browser's password manager on the web, never in local storage.
- Ctrl+K jumps to any channel, person, post number or command;
?shows the shortcuts. - Light, dark, high-contrast or the system's theme.
- Settings live in your user area on the server, shared with other clients where they have a common meaning. Other clients' settings are never touched.
- Encrypted connections (TLS) whenever the server offers them. Plain text is used only after you agree, and the top bar shows which you have. lyskomd has no TLS of its own, so a server needs a TLS front end such as stunnel; kom.lysator.liu.se has none today.
- Swedish and English. The language comes from your user area, your browser, or a switch on the login page.
- Modern words by default (channel, post, reply, reaction). LysKOM's classic words (möte, kommentar, markera) are a setting, on automatically for people who use the Emacs client.
- The version you're running is shown under Settings.
Running it from source
Against a local LysKOM server with test data:
tools/devserver-reset.sh # lyskomd 2.1.2 on 127.0.0.1:4894, wiped and seeded
tools/serve-web.sh # http://127.0.0.1:8080 (add a LAN address as argument to share it)
Log in as Test Testsson, password test. Every seeded user's password
is their first name in lower case (Anna Andersson/anna and so on);
the seeder prints them all. The admin is person 5, password gazonk.
The browser can't speak TCP, so the web app connects through kom-relay, a
small WebSocket-to-TCP forwarder that serve-web.sh starts. To reach another
server, point the relay at it: KOM=kom.lysator.liu.se:4894 tools/serve-web.sh.
The relay speaks TLS to the server when it can. The devserver offers TLS on
port 4896 with a test CA (devserver/tls/); serve-web.sh uses that by
default. Running a relay for the public is described in
docs/RELAY.md, and the Kubernetes setup Lysator runs in
docs/KUBERNETES.md.
The desktop app connects directly, to kom.lysator.liu.se unless you type
another server on the login page (the port is 4894 unless you add one) or
set NEOKOM_SERVER=host:port. During development, set
NEOKOM_SERVER=127.0.0.1:4894 so you don't use the real server. Set
NEOKOM_TLS_CA=devserver/tls/ca.pem and use port 4896 to get TLS against
the devserver. To run it from source, use cd app && dx serve --platform desktop; on Linux this needs the WebKitGTK development packages.
Clone with git clone --recurse-submodules.
Packages
The desktop app is packaged for Arch, Debian, Fedora and NixOS. Each
release on the
releases page
has the Arch, Debian and Fedora packages with their checksums. The
packaging workflow builds, installs and checks all four on every change to
the packaging and on every release.
| Distro | Build it yourself |
|---|---|
| Arch | packaging/arch/PKGBUILD (makepkg) |
| Debian 13 | cargo deb -p neokom --no-default-features --features desktop (cargo-deb) |
| Fedora | packaging/fedora/neokom.spec (rpmbuild -ba) |
| NixOS | nix run "git+https://forge.lysator.liu.se/littlefox/neokom" (add ?ref=refs/tags/vX.Y.Z for a release), or nix build in a checkout |
The web image forge.lysator.liu.se/littlefox/neokom-web is built and
checked on every release (web-image.yml); latest only moves to a
release that passed.
Tests
cargo test --workspace --features kom-client/tcp # unit tests
KOM_ADDR=127.0.0.1:4894 cargo test -p kom-client --features tcp -- --ignored # against a devserver
tools/e2e.sh # browser tests: desktop, Android and iPhone sizes, own servers
tools/desktop-smoke.sh # desktop app under Xvfb
tools/perf.sh LABEL # measurements on a big seeded meeting (tools/perf-table.py compares)
tools/desktop-perf.sh LABEL # desktop memory and CPU on the same data
tools/cargo-deny.sh # dependency audit: advisories, licences, sources
CI runs on forge's shared runners (.forgejo/workflows/) on every push:
lint and unit tests, a dependency audit, the web download size against its
budget (tools/wasm-size.sh), integration tests against a seeded lyskomd,
the Playwright browser suite, and a desktop smoke test. Separate workflows
cover the following:
- Soak: an hour-long session with the connection cut every other post,
nightly (
soak.yml). - Fuzzing: the protocol decoder, nightly with cargo-fuzz (
fuzz.yml). - Dependencies: weekly
cargo update, checked and opened as a PR (deps.yml). - Packages and the web image:
packaging.ymlandweb-image.yml.
Work happens on feature branches, which are merged when CI is green.
Releases are cut with tools/release.sh.
Layout
crates/kom-proto: Protocol A codec, no I/O. Types are generated from the spec. Fuzz targets are infuzz/.crates/kom-client: connection, caches, unread tracking, reading order, thread index, content and aux items, composer.crates/relay:kom-relay, WebSocket↔TCP for the browser build.crates/devseed:kom-seed, deterministic test data (and the big meeting for the measurements).app/: the Dioxus UI (web and desktop).e2e/: Playwright browser tests, ande2e/perf/for the measurements.packaging/: desktop entry, icon, PKGBUILD, RPM spec and the web image (packaging/docker/).flake.nixis at the root.devserver/: lyskomd in Docker.ci/: CI job images (tools/ci-images.sh).docs/:DESIGN.md,DECISIONS.md,ROADMAP.md(what comes next),DOCKER.md,KUBERNETES.md,RELAY.mdand the generated Protocol A grammar.tools/: scripts for the dev server, e2e, measurements, serving, releases, code generation, andforge.pyfor issues and CI.lyskom-server/,lyskom-elisp-client/: upstream sources as git submodules (reference and devserver build).
License
GPL-3.0-or-later, see LICENSE.