Skip to content

feat(selkies-project/selkies): add the Selkies desktop module - #1149

Open
ehfd wants to merge 2 commits into
coder:mainfrom
ehfd:selkies-module
Open

ehfd wants to merge 2 commits into
coder:mainfrom
ehfd:selkies-module

Conversation

@ehfd

@ehfd ehfd commented Sep 28, 2026 •

Copy link
Copy Markdown

Description

Adds a module that streams the workspace's desktop to the browser with Selkies, a low-latency remote desktop with audio in both directions, gamepads, and GPU encoding, behind a coder_app that Coder authenticates and proxies over one WebSocket, on a subdomain or a path.

  • Swappable with KasmVNC. The variables are the KasmVNC module's (agent_id, port, desktop_environment, subdomain, share, order, group), so a template swaps one for the other or offers both. desktop_environment also takes any installed session or a command, and empty starts the workspace's default desktop.
  • Install script. Where the workspace lacks selkies session (Selkies 2.1.0 or later) or Xvfb, it installs the release's native package, the distribution's Xvfb, and PulseAudio where the workspace has no sound server, as root or with passwordless sudo. It resolves the latest release from GitHub's releases/latest redirect rather than the API, whose 60 unauthenticated requests per hour everything behind one address shares, and checks the package against the release's SHA256SUMS (or, for a release published before it carried one, the digest GitHub records for the asset) before installing it. A workspace has Selkies only where selkies session --help answers as 2.1.0's does: an older selkies takes the word for a stray argument and starts a bare server, so it counts as missing, and after installing the script checks again. install_selkies = false installs nothing, for images that carry Selkies; selkies_version and release_url pin a release and a mirror.
  • Start script. Starts selkies session on the loopback addresses without a login or TLS of its own and waits until /api/health answers, checked over bash's /dev/tcp so it needs no curl. It reports a launcher that exits first with the end of its log, and leaves a running one alone.
  • Registry conventions. Scripts run through coder-utils 0.0.2, and data and logs live under $HOME/.coder-modules/selkies-project/selkies/. The new selkies-project namespace, the upstream GitHub organization, gets a README and an avatar. The /icon/selkies.svg the app and scripts show is added to coder/coder in chore(site): add selkies icon coder#30026.

Selkies streaming an XFCE desktop from a codercom/example-desktop workspace

Type of Change

  • New module

Module Information

  • Path: registry/selkies-project/modules/selkies
  • New version: v1.0.0
  • Breaking change: No

Testing & Validation

  • Tests pass (bun test): main.test.ts 6 passed, 0 failed (31 assertions) against a real Docker daemon, a pre-2.1.0 selkies among them; terraform test 11 passed, 0 failed with Terraform 1.16.4, the registry's coder-utils 0.0.2, and provider coder/coder 2.18.0.
  • Code formatted (bun fmt): bun run fmt:ci, typos, go run ./cmd/readmevalidation, scripts/terraform_validate.sh, and scripts/shellcheck_validate.sh pass, and the rendered scripts are shellcheck-clean at -S style.
  • Changes tested locally with Selkies 2.1.0, in a Coder v2.37.5 deployment with a Docker template, through Chrome 155, Firefox 158, and WebKit 27.2:
    • codercom/example-desktop (Ubuntu 26.04, XFCE): the install script installed selkies-2.1.0-ubuntu26.04-amd64.deb, checked against the release's SHA256SUMS, with Xvfb and PulseAudio, using sudo. The app was healthy about a minute after the build. The desktop streamed at 60 fps in all three browsers, both as a subdomain app and as a path app. Through Coder's proxy, a WebSocket upgrade from the page's origin got 101, and one from another site's origin got 403.
    • Debian 13 with XFCE: selkies-2.1.0-debiantrixie-amd64.deb, Xvfb, and PulseAudio installed; healthy 36 s after the workspace was created; 60 fps in all three browsers, from the first connection on.
    • install_selkies = false on the Selkies desktop image (2.1.0), without sudo: nothing installed; healthy 10 s after the workspace was created; 60 fps in all three browsers.
    • wayland = true with an NVIDIA GPU: LXQt's Wayland session on Selkies' Wayland backend, captured zero-copy and encoded on NVENC; 60 fps in all three browsers.

On Debian 13, Selkies 2.0.0 aborted at the first connection when the agent's SSH_CONNECTION reached it while a sound server ran, because pcmflux 2.1.0's wheel bundled a second libxcb. Selkies 2.1.0 carries the fix (selkies-project/pcmflux@a85622b): the first connection to a freshly created Debian 13 workspace streamed normally, as did every later one, with one Selkies process throughout.

Related Issues

coder/coder#2106, selkies-project/selkies#64, coder/coder#30026 (the icon), and selkies-project/selkies#421 (the same fixes in Selkies' own Coder module).

Copilot AI lite review requested due to automatic review settings September 28, 2026 02:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@bpmct

bpmct commented Sep 28, 2026

Copy link
Copy Markdown
Member

/scorecard

@github-actions

Copy link
Copy Markdown
Contributor

Module Scorecard Check

selkies-project/selkies: first scorecard, 93 / 100

No specific score is required to contribute, but modules with higher scores are more likely to be approved by the Coder team and widely used.

Full scorecard for this PR
Presentation & Onboarding Credential Hygiene Restricted-Environment Readiness Engineering Quality Overall
17 / 17 16 / 20 19 / 20 10 / 10 93 / 100
Drilldown

Track: Utility (desktop-streaming tool — not an AI agent or code editor)

Presentation & Onboarding — 17 / 17

Criterion Max Score Notes
Configuration-mode examples 12 12 README documents every major mode: default apply, image-carries-Selkies (install_selkies = false), pinned-version + release_url mirror install, and wayland = true. Each shows a complete, sensible module block.
Visual preview 5 5 ![Selkies desktop in a Coder workspace](../../.images/selkies-desktop.png) embedded and verified to exist.

Credential Hygiene — 16 / 20

Criterion Max Score Notes
Secrets marked sensitive 16 16 Module has no secret-bearing inputs at all; no inline keys or tokens appear anywhere in the README examples.
Non-hardcoded auth path 4 0 The only relevant line — "Coder authenticates the app and proxies it over one WebSocket" — describes Coder's app-proxy access control, not an external-service credential path (no IAM/OAuth/API-key-helper/AI-Gateway pattern is shown or needed). Doesn't meet the intent of the criterion.

Restricted-Environment Readiness — 19 / 20

Criterion Max Score Notes
Mirrorable artifact source 5 5 release_url variable overrides the base URL used for <release_url>/latest and <release_url>/download/<version>/<file> in install.sh.tftpl; documented in "Installing at Start" with a mirror example.
Bring-your-own binary 10 10 install_selkies = false fully disables install when the image already carries Selkies/Xvfb; documented in "Selkies in the Image" with its own example.
Egress transparency 3 3 Dedicated "## Network Access" section enumerates exact contacted endpoints (<release_url>/latest, <release_url>/download/..., distro package repos) and states runtime traffic stays on Coder's proxy/loopback.
Runs without sudo 2 1 Default install path requires root or passwordless sudo for package installation (core install function) and only prints an error otherwise — no in-script non-root fallback. A complete no-sudo path exists only via the separate install_selkies = false mode (BYOB), so this is "optional-feature sudo with a working fallback" → half credit. Start script itself never uses sudo.

Engineering Quality — 10 / 10

Criterion Max Score Notes
Input quality 6 6 All variables have clear descriptions and sensible defaults; validation blocks on port, share, selkies_version, and release_url.
Test coverage 4 4 main.tftest.hcl covers business logic thoroughly (defaults, healthcheck, KasmVNC-parity vars, desktop command quoting, wayland, BYOB mode, mirrored/pinned release, and all validation rejections). main.test.ts exercises real install/start scripts in containers, including failure and idempotency paths.

Overall — 93 / 100

Raw 62 / 67 → round(62 / 67 × 100) = 93

Tip

You can run this locally by telling your agent: "review this module against .github/scorecard/SCORECARD.md".


Scored against SCORECARD.md with solstice-1. Language-model scores are advisory.

@ehfd
ehfd force-pushed the selkies-module branch 2 times, most recently from b73c1f6 to 82635c8 Compare October 2, 2026 07:13
@ehfd
ehfd marked this pull request as draft October 19, 2026 16:46
@ehfd
ehfd force-pushed the selkies-module branch 2 times, most recently from 313e863 to 3b49b8d Compare October 20, 2026 08:13
@ehfd
ehfd marked this pull request as ready for review October 21, 2026 05:03
ehfd added 2 commits October 21, 2026 19:16
Stream the workspace's desktop to the browser with Selkies behind a
coder_app, with the KasmVNC module's variables so a template swaps one for
the other. The install script installs what the workspace lacks of Selkies
and Xvfb, with PulseAudio where no sound server is installed, from the
release's native package and the distribution, as root or with passwordless
sudo, or nothing with install_selkies = false; the package is checked
against the release's SHA256SUMS, or the digest GitHub records for it,
before it is installed. The start script starts selkies-session on the
loopback addresses, without a login or TLS of its own, and waits until it
answers.
Selkies 2.1.0 runs its tools as subcommands, so the module starts the
desktop with `selkies session` rather than `selkies-session`, and takes a
workspace to have Selkies only where `selkies session --help` answers as
2.1.0's does: an older selkies takes the word for a stray argument and
starts a bare server. After installing, it checks again and says to pick
2.1.0 or later. The session's log is session.log.

The defaults test now checks that the latest release is resolved through
GitHub's redirect rather than the API's releases/latest; the API stays the
digest fallback for a release published without SHA256SUMS.
@ehfd

ehfd commented Oct 21, 2026

Copy link
Copy Markdown
Author

@DevelopmentCats Ready for review again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants