Skip to content

feat: add Nix flake dev environment#29

Open
yuuhikaze wants to merge 3 commits into
Open-LLM-VTuber:mainfrom
yuuhikaze:feat/nix-flake-dev
Open

feat: add Nix flake dev environment#29
yuuhikaze wants to merge 3 commits into
Open-LLM-VTuber:mainfrom
yuuhikaze:feat/nix-flake-dev

Conversation

@yuuhikaze

@yuuhikaze yuuhikaze commented Jun 15, 2026

Copy link
Copy Markdown

Summary

Adds a Nix flake for a reproducible development environment, mainly aimed at NixOS users who can't run the npm-bundled Electron binary out of the box (missing dynamic libraries, no hardcoded RPATHs).

What it does

The flake provides a dev shell with Node.js and a NixOS-patched Electron binary. It sets ELECTRON_EXEC_PATH so electron-vite picks up the system Electron instead of the one from node_modules — no LD_LIBRARY_PATH hacks needed.

Includes a .envrc for direnv users: run direnv allow once and the environment loads automatically every time you cd into the project.

For non-NixOS users

This changes nothing. The flake and .envrc are inert unless you have Nix installed. The regular npm install && npm run dev workflow is unchanged.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a Nix flake–based development environment with Node.js and Electron, including a ready-to-use setup recommended for NixOS users.
  • Documentation
    • Expanded README with NixOS setup guidance (direnv/nix-direnv) and an alternative manual nix develop workflow, plus updated Electron environment notes.
  • Chores
    • Updated environment and ignore settings for smoother flake/direnv usage and to exclude local editor/cache files.
    • Added an audio-related shell environment setting for better in-session behavior.

Add Nix flake with NixOS-patched Electron binary and direnv
integration for reproducible development setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 365e3157-f2f0-4f01-bd4c-5000715783f5

📥 Commits

Reviewing files that changed from the base of the PR and between f9ebaa0 and 31c2a3a.

📒 Files selected for processing (1)
  • flake.nix
🚧 Files skipped from review as they are similar to previous changes (1)
  • flake.nix

📝 Walkthrough

Walkthrough

Adds Nix flake support for NixOS users. A new flake.nix defines a development shell with nodejs and electron, setting ELECTRON_EXEC_PATH to the Nix-provided binary. .envrc activates the flake via direnv, .gitignore excludes local files, and README.md documents the Nix setup workflow.

Changes

Nix development environment

Layer / File(s) Summary
Flake shell integration
flake.nix, .envrc, .gitignore
Defines per-system development shells with Node.js and Electron, configures Electron and PulseAudio/PipeWire environment variables, enables direnv activation, and ignores local environment artifacts.
Nix setup documentation
README.md
Documents direnv and manual nix develop workflows, including use of the flake-provided Electron binary without LD_LIBRARY_PATH exports.

Estimated code review effort: 2 (Simple) | ~8 minutes

Poem

🐇 A Nix flake blooms today,
Direnv guides the shell’s way.
Electron waits, neatly spun,
Node.js joins in the run.
Local caches hide from sight—
The rabbit hops through setup bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a Nix flake development environment.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 11-30: The README.md documentation at line 29 references an
incorrect environment variable name `ELECTRON_OVERRIDE_DIST_PATH`, but the
actual flake.nix implementation sets `ELECTRON_EXEC_PATH`. Update the README.md
to replace the environment variable reference from `ELECTRON_OVERRIDE_DIST_PATH`
to `ELECTRON_EXEC_PATH` to match the actual implementation and keep the
documentation accurate with how electron-vite reads this variable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 90127b66-ddde-4cd9-8d01-98380da145e4

📥 Commits

Reviewing files that changed from the base of the PR and between d176e7d and 6b4a133.

⛔ Files ignored due to path filters (1)
  • flake.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • .envrc
  • .gitignore
  • README.md
  • flake.nix

Comment thread README.md
yuuhikaze and others added 2 commits June 16, 2026 08:30
ELECTRON_OVERRIDE_DIST_PATH → ELECTRON_EXEC_PATH to match flake.nix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@yuuhikaze

Copy link
Copy Markdown
Author

Added a small quality-of-life feature to the dev shell: audio streams from the app are now tagged with media.role=Assistant via PULSE_PROP_OVERRIDE. libpulse (which Chromium's audio service uses) reads this env var and applies the property to every stream the app creates, at the source.

Why tag at the source? All Electron apps look identical to PipeWire (application.name = "Chromium input", application.process.binary = "electron"), so there is no server-side rule that can single out this app. The env var makes the streams individually addressable, which enables audio ducking: lowering music/video volume while the VTuber speaks.

To benefit from it on NixOS, pair the tag with a WirePlumber role-based linking policy. Sample configuration:

services.pipewire.wireplumber.configPackages = [
  (pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/50-ducking.conf" ''
    wireplumber.profiles = {
      main = {
        policy.linking.role-based.loopbacks = required
      }
    }

    wireplumber.settings = {
      node.stream.default-media-role = Multimedia
      linking.role-based.duck-level = 0.15
    }

    wireplumber.components.rules = [
      {
        matches = [
          {
            provides = "~loopback.sink.*"
          }
        ]
        actions = {
          merge = {
            arguments = {
              capture.props = {
                policy.role-based.target = true
                audio.position = [ FL, FR ]
                media.class = Audio/Sink
              }
              playback.props = {
                node.passive = true
                media.role = Loopback
              }
            }
            requires = [ support.export-core, pw.node-factory.adapter ]
          }
        }
      }
    ]

    wireplumber.components = [
      {
        type = virtual, provides = policy.linking.role-based.loopbacks
        requires = [ loopback.sink.role.multimedia
                     loopback.sink.role.assistant ]
      }
      {
        name = libpipewire-module-loopback, type = pw-module
        arguments = {
          node.name = "loopback.sink.role.multimedia"
          node.description = "Multimedia"
          capture.props = {
            device.intended-roles = [ "Music", "Movie", "Game", "Multimedia" ]
            policy.role-based.priority = 10
            policy.role-based.action.same-priority = "mix"
            policy.role-based.action.lower-priority = "mix"
          }
        }
        provides = loopback.sink.role.multimedia
      }
      {
        name = libpipewire-module-loopback, type = pw-module
        arguments = {
          node.name = "loopback.sink.role.assistant"
          node.description = "Assistant"
          capture.props = {
            device.intended-roles = [ "Assistant" ]
            policy.role-based.priority = 50
            policy.role-based.action.same-priority = "mix"
            policy.role-based.action.lower-priority = "duck"
          }
        }
        provides = loopback.sink.role.assistant
      }
    ]
  '')
];

With this in place, regular streams (untagged, defaulting to Multimedia) route through the Multimedia sink, the VTuber's Assistant-role streams route through the Assistant sink, and WirePlumber ducks Multimedia to 15% volume whenever the VTuber speaks. The custom Assistant role (instead of Communication) avoids collateral ducking from apps like Discord that tag their own call streams as Communication.

The tag is harmless on non-PipeWire/PulseAudio setups — it is only read by libpulse clients.

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.

1 participant