The new new lyskom client. 100% vibe-coded...
  • Rust 67.7%
  • TypeScript 17.3%
  • D 5.6%
  • CSS 3.2%
  • Shell 2.9%
  • Other 3.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Johan Holtz 1c2d581fbe
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
Merge pull request 'Release 0.7.1' (#340) from release-0.7.1 into main
2026-10-25 09:52:00 +00:00
.forgejo/workflows Perf budgets: times from CI's first run 2026-10-23 01:10:47 +00:00
app Phones: a channel's head in two rows; no "Status för X." 2026-10-25 07:22:25 +00:00
ci Stay logged in: keyring on the desktop, name and server in the browser 2026-10-17 22:17:31 +00:00
crates An image with text: the text, then the image as a footnote (D-067) 2026-10-24 21:40:47 +00:00
devserver Measure first: a big meeting, a perf spec and a desktop memory run 2026-10-21 22:29:39 +00:00
docs Phones: a channel's head in two rows; no "Status för X." 2026-10-25 07:22:25 +00:00
e2e Test: going to a passive membership shows its status, the name as heading 2026-10-25 07:45:21 +00:00
lyskom-elisp-client@99b646108e Track upstream LysKOM sources as submodules, add GPL-3.0 license 2026-10-16 15:51:52 +00:00
lyskom-server@510601bb38 Track upstream LysKOM sources as submodules, add GPL-3.0 license 2026-10-16 15:51:52 +00:00
packaging Release 0.7.1 2026-10-25 09:02:10 +00:00
tools forge.py pr-merge: a skipped run doesn't block a merge 2026-10-23 19:59:46 +00:00
.dockerignore HTTPS mode for the Docker image: installable on the home network 2026-10-18 11:51:14 +00:00
.gitignore Add Forgejo Actions CI on a sonder runner; move tasks to issues 2026-10-16 17:13:39 +00:00
.gitmodules Track upstream LysKOM sources as submodules, add GPL-3.0 license 2026-10-16 15:51:52 +00:00
Cargo.lock Release 0.7.1 2026-10-25 09:02:10 +00:00
Cargo.toml Release 0.7.1 2026-10-25 09:02:10 +00:00
CHANGELOG.md Changelog: what 0.7.1 is about 2026-10-25 09:02:22 +00:00
CLAUDE.md Close covering panes at the click, not when the post arrives 2026-10-20 13:40:23 +00:00
clippy.toml Make clippy pedantic clean across the workspace 2026-10-18 08:43:04 +00:00
deny.toml Dependency audit (cargo-deny, npm audit) and weekly update PRs 2026-10-17 21:37:13 +00:00
flake.lock Make nix run from a git URL work: commit flake.lock, use refs/tags 2026-10-17 16:47:42 +00:00
flake.nix Release 0.7.1 2026-10-25 09:02:10 +00:00
LICENSE Track upstream LysKOM sources as submodules, add GPL-3.0 license 2026-10-16 15:51:52 +00:00
README.md README: catch up with 0.3 to 0.6 2026-10-22 09:23:16 +00:00

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.yml and web-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 in fuzz/.
  • 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, and e2e/perf/ for the measurements.
  • packaging/: desktop entry, icon, PKGBUILD, RPM spec and the web image (packaging/docker/). flake.nix is 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.md and the generated Protocol A grammar.
  • tools/: scripts for the dev server, e2e, measurements, serving, releases, code generation, and forge.py for 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.