Introduction
Cardwire is a GPU manager for Linux laptops and multi-GPU desktops. It allows users to block the GPU of their choice, and to route applications on a specific GPU.
Why Cardwire?
Traditional GPU managers for Linux (like envycontrol, optimus-manager, supergfxctl) often require system restarts or display manager logouts, and were made with laptops in mind. And other built-in tools (like switcheroo-control) are great for launching apps but don’t actively protect the dedicated GPU from being woken up, cannot force an application to run on a specific GPU.
Cardwire solves this by using eBPF and LSM to dynamically block access to the GPU (more info about those here). This ensures the GPU is blocked at a userspace level.
Furthermore, unlike older managers, Cardwire never unbinds PCI devices or unload kernel drivers. Unbinding drivers on the fly is notoriously unstable and is a frequent cause of crashes on AMD GPUs or system deadlocks on NVIDIA GPUs. Cardwire’s eBPF approach is entirely seamless and significantly more stable.
Modes
Cardwire provides several GPU management modes:
-
Integrated mode - Block applications from accessing dedicated GPU, leaving only the iGPU available
-
Hybrid mode - Removes the blocks, letting the system function normally with all GPUs available.
-
Manual mode - Allows users to manually block or unblock individual GPUs by ID for granular control. It is only available on desktop systems and never blocks the default GPU.
-
Smart mode - Like integrated mode it blocks the dGPU by default, but a userspace analyzer inspects each application at launch and selectively allows GPU access for approved applications.
Warning
Integrated and Smart mode are only available for laptops, desktop/multi-gpus have access to Hybrid & Manual
Switching between modes is fast and does not require reboots or logouts.
Caution
Cardwire is in an early development stage, expect breaking changes.
Getting Started
To get started with cardwire, please take a look at the requirements to make sure your system is supported and configured, then head over to the installation instructions.
Requirements
To run Cardwire, your system needs to meet a few core requirements. Good news: if you are using a modern Linux distribution, you likely already meet all of these out of the box!
1. Supported Distributions (Kernel & System)
Cardwire requires:
- Linux Kernel 5.8 or later (with
CONFIG_BPF_LSMenabled). - systemd as the init system.
Tip
The following distributions are known to work out of the box with zero manual configuration required:
- OGC Distros (Officially Supported): see ogc website
- NixOS (Officially Supported)
- Arch Linux / CachyOS
- Fedora (and Atomic variants)
- Debian/Ubuntu
If you are using one of these distributions, you can safely skip the advanced verification below and head straight to the Installation Guide.
Warning
Non-systemd distros are currently not supported. If you want to use Cardwire on a non-systemd distro, either open a PR with patches or configure the required services on your setup.
2. Display Server
Caution
Cardwire only supports Wayland. X11 is unsupported.
Advanced: Manual Kernel Verification
If you are not using a distribution listed above, or if you are compiling your own kernel, you will need to manually verify that eBPF LSM is enabled.
1. Verify CONFIG_BPF_LSM is enabled
On e.g. Ubuntu/Fedora:
grep CONFIG_BPF_LSM /boot/config-$(uname -r)
On other distros possibly:
zcat /proc/config.gz | grep CONFIG_BPF_LSM
Returns
CONFIG_BPF_LSM=yif it’s enabled.
2. Verify BPF is in the boot cmdline
Check your current boot parameters:
cat /proc/cmdline | tr ' ' '\n'|grep lsm
Alternative methods:
grep CONFIG_LSM= /boot/config-$(uname -r)
or
zcat /proc/config.gz | grep CONFIG_LSM=
Outputs e.g.
lsm=landlock,yama,apparmor,bpforCONFIG_LSM="landlock,lockdown,yama,integrity,apparmor,bpf". If it contains ‘bpf’, bpf is already enabled and usable in your system!
3. Verify BPF LSM is active at runtime
The cardwire daemon refuses to start without this. Check the list of active LSMs:
cat /sys/kernel/security/lsm
Must contain
bpf. If it does, eBPF LSM is ready even if the boot cmdline looks different.
Enabling BPF LSM (with GRUB)
If bpf is not in your boot cmdline, edit /etc/default/grub and append bpf to GRUB_CMDLINE_LINUX_DEFAULT, keeping all existing entries:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash lsm=landlock,lockdown,yama,integrity,apparmor,bpf"
Important
Do not set
lsm=bpfalone, that drops other active security policies. Always appendbpfto the existing list from the command above.
Apply and reboot:
| Distro | Command |
|---|---|
| Ubuntu | sudo update-grub |
| Fedora | sudo grub2-mkconfig -o /boot/grub2/grub.cfg |
| Arch | sudo grub-mkconfig -o /boot/grub/grub.cfg |
sudo reboot
Installation
Arch/CachyOS/Arch-based
The official Open Gaming Collective Arch packages are available here: ogc-arch-packaging
Alternatively, using the AUR:
yay -S cardwire
And start the service:
sudo systemctl enable cardwired --now
Nix
Using nixpkgs-unstable (recommended)
services.cardwired = {
enable = true;
settings = {
auto_apply_gpu_state = true;
experimental_nvidia_block = true;
battery_auto_switch = true;
battery_auto_switch_mode = "hybrid";
external_display_auto_switch = false;
};
}
Using the repo’s flake (This will be dropped when cardwire hits nixpkgs-26.11):
flake.nix:
cardwire = {
url = "github:opengamingcollective/cardwire";
inputs.nixpkgs.follows = "nixpkgs";
};
configuration.nix:
imports = [ inputs.cardwire.nixosModules.default ];
services.cardwire = {
enable = true;
settings = {
auto_apply_gpu_state = true;
experimental_nvidia_block = true;
battery_auto_switch = true;
battery_auto_switch_mode = "hybrid";
external_display_auto_switch = false;
};
};
Fedora/Fedora-based
Cardwire is officially distributed through Terra on Fedora systems
To install Terra, follow the instructions here: https://docs.terrapkg.com/usage/installing
Using Terra
sudo dnf install cardwire
And start the service:
sudo systemctl enable cardwired --now
Bazzite
Cardwire is installed out-of-the-box
Atomic Fedora-based
Cardwire is officially distributed through Terra on Fedora systems
To install Terra, follow the instructions here: https://docs.terrapkg.com/usage/installing
Using Terra
sudo rpm-ostree install cardwire
And start the service:
sudo systemctl enable cardwired --now
Note
Thanks to the Fyra Labs / Terra team for packaging and maintaining Cardwire on Fedora !!
AerynOS
Cardwire is available in the official AerynOS repositories.
sudo moss install cardwire
And start the service:
sudo systemctl enable cardwired --now
Ubuntu / Debian
A .deb package is available on the releases page. You can download and install it using apt.
sudo apt install ./cardwire_*.deb
sudo systemctl enable cardwired --now
Build from source (Alternative)
Install build dependencies:
sudo apt install libbpf-dev libudev-dev pkg-config libegl1-mesa-dev libvulkan-dev libglvnd-dev libwayland-dev libxkbcommon-dev libx11-dev libxcb1-dev libx11-xcb-dev
Install Rust (if not already installed):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Install bpf-linker
cargo binstall bpf-linker
Then clone and build:
git clone https://github.com/OpenGamingCollective/cardwire.git
make build
sudo make install
And start the service:
sudo systemctl enable cardwired --now
Other distros
For now, other distros must clone the repo and use make to build and install Cardwire. You will also need to enable BPF LSM manually, see the Enabling BPF LSM (with GRUB) section above.
Build dependencies:
- cargo (plus
bpf-linkerand a pinned nightly toolchain for the eBPF program) - libudev-dev
- pkg-config
- Vulkan, EGL, Wayland and X11 development packages (GUI build)
git clone https://github.com/OpenGamingCollective/cardwire.git
make build
sudo make install
And start the service:
sudo systemctl enable cardwired --now
Usage
Querying GPUs
To have cardwire list all detected GPUs, use:
cardwire list
For each detected GPU, the command will return:
- An identifier (
ID). These are used for manual blocking and unblocking. - The GPU’s name (
NAME) - The GPU’s PCI address (
PCI) - The associated render node (
RENDER) - The associated device node (
CARD) - Whether the GPU has been identified as the default GPU (
DEFAULT). Default GPUs will remain available when cardwire is set to integrated. - Whether the GPU is a discrete GPU (
DISCRETE) - Whether the GPU is currently blocked (
BLOCKED)
--json prints the full device map as JSON.
--full prints the full pci device map as JSON.
Example:
$ cardwire list
ID NAME PCI RENDER CARD DEFAULT DISCRETE BLOCKED
-- ------------------------------------------- ------------ ---------- ----- ------- -------- -------
0 Rembrandt [Radeon 680M] 0000:07:00.0 renderD129 card2 (*) ( ) false
1 Navi 23 [Radeon RX 6650 XT / 6700S / 6800S] 0000:03:00.0 renderD128 card1 ( ) (*) true
Mode switching
To print the current mode:
cardwire get
GPU modes can be switched using the cardwire set command.
Integrated
To have cardwire block the dGPU, use:
cardwire set integrated
Note
The block only applies to new launched apps. Apps that are already running will keep using the GPU until you restart them. Restarting can help.
Tip
The dedicated GPU can still power down even if your desktop has it open, as long as nothing is actively using it. To double-check, run:
cardwire gpu 1 --lsof
Hybrid
To have cardwire allow access to all GPUs, use
cardwire set hybrid
Smart Mode
Smart mode blocks the dedicated GPU by default like integrated mode, but uses a real-time analyzer to scan each application at launch and selectively allow GPU access for approved apps.
Cardwire natively integrates with desktop environments (GNOME, KDE) via a Switcheroo DBus shim. This means you can simply right-click an application in your app launcher and select “Launch using Discrete Graphics Card”, and Cardwire will automatically unblock the GPU for that application.
Tip
When an application is launched via the Switcheroo UI or with
CARDWIRE_FORCE_DGPU=1, Cardwire will hide the integrated GPU (iGPU) from the app. The app will only be able to see and use the dedicated GPU, guaranteeing it runs on the correct hardware.
When launching apps in Smart mode, cardwire checks for the following to allow the dGPU:
CARDWIRE_ALLOW=1env var (highest priority, unblocks the GPU but doesn’t force the app to use it)CARDWIRE_FORCE_DGPU=1env var (unblocks the GPU, forces the app to use it, and completely hides the iGPU)CARDWIRE_FORCE_GPU=<gpu_id>env var (unblocks a specific GPU and forces the app to use it)- Steam games, identified by
SteamAppId, are discovered into the internal application list and blocked by default until allowed - The per-app policies stored in cardwire’s internal application list
Note
The former auto-approval inputs are deprecated in favor of the internal application list. Steam auto-allow,
PrefersNonDefaultGpudesktop entries and the automatic approval of GPU environment variables (DRI_PRIME,__NV_PRIME_RENDER_OFFLOAD) are no longer evaluated.
cardwire set smart
Note
This feature is a work in progress. The detection methods will be improved in future updates.
Manual
Important
To prevent system breakage, cardwire will not block the default GPU, even when explicitly instructed to do so.
If more granular control over several GPUs is required, cardwire also allows manually blocking individual GPUs by ID. To do so, it needs to be set to manual mode:
cardwire set manual
Once set to manual, GPU states can then be set by ID. To find the correct ID, see Querying GPUs.
To block the GPU with ID 1:
cardwire gpu 1 --block
To unblock:
cardwire gpu 1 --unblock
Launching apps on a specific GPU
cardwire launch starts a program with the right GPU environment set, without switching modes:
cardwire launch --gpu 1 nvtop
cardwire launch glxgears
Without --gpu, cardwire picks the best GPU for the job, in this order: a discrete non-default GPU, a discrete GPU, the default GPU, then the first available one. The command fetches the launch environment from the daemon.
Launching on a blocked or unavailable GPU is refused with a clear error, switch to Smart mode or unblock the GPU first.
System information
To check that the daemon is running:
cardwire manager status
To refresh the GPU list held by the daemon (useful after a hotplug event):
cardwire debug refresh-gpu
To check the power state of a GPU (for example whether it reached D3Cold):
cardwire gpu 1 --power
Configuration
Experimental Nvidia Block
Note
This setting is experimental because it tells cardwire to block specific Nvidia files, such as /dev/nvidiactl, that can be shared across multiple Nvidia GPUs. For this reason, it only works reliably on systems with exactly two GPUs: one integrated GPU and one dedicated Nvidia GPU.
Tip
Even though it is experimental, enabling this setting is recommended. It helps prevent unwanted GPU wakeups from Vulkan apps (GTK on gnome) and from tools that use /dev/nvidiactl, such as nvtop
To get if experimental Nvidia block is enabled:
cardwire config experimental-nvidia-block
To enable/disable it:
cardwire config experimental-nvidia-block true
Battery Auto Switch Mode
Cardwire can automatically switch GPU modes when the system switches between battery and AC power. When battery_auto_switch is enabled, cardwire switches to integrated mode on battery and back to a configurable mode when on AC power.
To get if battery auto switch is enabled:
cardwire config battery-auto-switch
To enable/disable it:
cardwire config battery-auto-switch true
The mode cardwire switches to on AC power is controlled by battery_auto_switch_mode. This can be set to integrated, hybrid, manual, or smart.
To get the current battery auto switch mode:
cardwire config battery-auto-switch-mode
To set the battery auto switch mode:
cardwire config battery-auto-switch-mode hybrid
External Display Auto Switch
When an external display is connected to a port wired directly to the dedicated GPU, Cardwire can temporarily switch Integrated and Smart modes to Hybrid. It restores the requested mode after the display is disconnected.
This feature is disabled by default. To get if external display auto switch is enabled:
cardwire config external-display-auto-switch
To enable/disable it:
cardwire config external-display-auto-switch true
Auto Apply Gpu State
When you switch back to manual mode, this setting automatically restores the GPU states you had set before. These saved states are stored in /var/lib/cardwire/gpu_state.json
To view the current saved states, run:
cat /var/lib/cardwire/gpu_state.json
Example output:
{
"0000:03:00.0": {
"block": false
},
"0000:07:00.0": {
"block": false
}
}
In this example, both GPUs are set to allow access (block: false) when manual mode is restored
To get the current setting:
cardwire config auto-apply-gpu-state
To set the setting:
cardwire config auto-apply-gpu-state true
Troubleshooting
Name is not activable
Is the daemon running?
systemctl status cardwired.service
If it’s not running, enable the daemon with
systemctl enable cardwired.serviceand reboot your device.
dGPU is detected as the default gpu
On ROG laptop
is the asus MUX enabled?
asusctl armoury list
then find
gpu_mux_mode:
current: [(0),1]
0 means that the MUX is disabled, the dGPU IS the default GPU in this case
To enable it:
asusctl armoury set gpu_mux_mode 1
A reboot is required for the change to take effect.
Non ROG Laptop
This shouldn’t happen, please create an issue with the output of
ls /sys/class/drm
and
cat /sys/class/drm/*/status
nvidia-powerd failure after switching modes
When switching to integrated mode on NVIDIA hardware, you may see errors or failures related to the nvidia-powerd service. This is a known quirk caused by the GPU entering D3Cold (a deep sleep state) which prevents nvidia-powerd from communicating with it.
Since v0.12.0, cardwired restarts nvidia-powerd automatically after every mode change (only when the service is enabled), so this is usually fixed without any action. If the problem persists, restart it manually:
sudo systemctl restart nvidia-powerd.service
Note
This was fixed in cardwire 0.12.1, cardwired now stop and start nvidia-powerd on mode switch instead of a naive restart
Sleep
How to diagnose a dGPU that won’t sleep
Your dGPU won’t sleep? Here’s how to find and fix the issue.
Check your NVIDIA GPU power information
Before this, please set cardwire to unblock your dGPU.
Replace the PCI with yours.
cat /proc/driver/nvidia/gpus/0000:01:00.0/power
Runtime D3 status: Enabled (fine-grained)
Video Memory: Off
GPU Hardware Support:
Video Memory Self Refresh: Supported
Video Memory Off: Supported
S0ix Power Management:
Platform Support: Supported
Status: Enabled
Notebook Dynamic Boost: Not Supported
The most important section should be Runtime D3 status.
If Runtime D3 status is disabled, your GPU will never sleep.
To enable it, follow this method (only tested on Arch, please adapt it for other distros):
Caution
If you lack the knowledge, or you fear you will break your system, you can always make a post on the Discord to get assistance.
Go to https://gitlab.com/asus-linux/nvidia-laptop-power-cfg.
We will need two files:
- nvidia.rules
- nvidia.conf
You will need to copy them to their respective directory: For nvidia.conf:
/etc/modprobe.d/nvidia.conf
For nvidia.rules:
/usr/lib/udev/rules.d/80-nvidia-pm.rules
Once it’s done, execute:
sudo mkinitcpio -P
and restart your computer.
RTX 2000 Series
If it’s not working and you own an RTX 2000 GPU, it’s a known issue.
You must use driver 580 and add NVreg_EnableGpuFirmware=0 to /etc/modprobe.d/nvidia.conf.
Check the PCI control value
cat /sys/bus/pci/devices/0000:03:00.0/power/control
If it says auto, you can skip this, if it says on/off, try this command to set the control to auto:
echo "auto" | sudo tee cat /sys/bus/pci/devices/0000:03:00.0/power/control
Packaging
This is a note for packagers trying to package cardwire
All cardwire crates can be built with rustc stable, excepted cardwire-ebpf.
RUSTC And BPF Target
cardwire-ebpf is built by cardwire-ebpf-userspace, and require either rustc nightly (BPF target is tier 3) or enabling the bpf target directly in rustc
With a rustc built with bpf enabled:
'RUSTC_BOOTSTRAP=1 cargo build -p cardwire-ebpf-userspace'
Should work
LLVM
Another issue that can happen while trying to build cardwire-ebpf-userspace is having bpf-linker errors.
Types of error i encountered:
memset error
This one happens when using a bpf-linker either statically linked to llvm <=22
❯ strings $(which bpf-linker) | grep -m3 -iE "LLVM version"
LLVM version 22.1.8
or dynamically linked:
test@archlinux ~> ldd $(which bpf-linker)
linux-vdso.so.1 (0x00007f73bb2fd000)
libLLVM.so.22.1 => /usr/lib/libLLVM.so.22.1 (0x00007f73b0a00000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f73bb2a7000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f73b0600000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f73bb2ff000)
libffi.so.8 => /usr/lib/libffi.so.8 (0x00007f73bb299000)
libedit.so.0 => /usr/lib/libedit.so.0 (0x00007f73bb25d000)
libz.so.1 => /usr/lib/libz.so.1 (0x00007f73bb240000)
libzstd.so.1 => /usr/lib/libzstd.so.1 (0x00007f73baf1a000)
libxml2.so.16 => /usr/lib/libxml2.so.16 (0x00007f73b08ca000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f73b0200000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f73b00c9000)
libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f73baea9000)
libicuuc.so.78 => /usr/lib/libicuuc.so.78 (0x00007f73afe00000)
libicudata.so.78 => /usr/lib/libicudata.so.78 (0x00007f73ade00000)
To fix this issue, please use a bpf-linker that’s linked to LLVM 23
Smart
Goal and integration
Cardwire owns its per-application policy. It does not depend on desktop environment heuristics like PrefersNonDefaultGPU or on DRI_PRIME, __NV_PRIME_RENDER_OFFLOAD or SteamAppId being present in the app environment. Those auto-approval inputs were dropped in 0.12.0 and replaced by the internal application policy (Smart Policy), which makes cardwire self-sufficient while staying compatible with desktop environments through the Switcheroo shim.
Third parties that want to integrate with cardwire get three methods:
- Env: the
CARDWIRE_environment variables is a way to route a process to a GPU, The per-GPU environment can be fetched from theEnvproperty of the GPU API. The env will always have priority over the other methods. - PID via API:
RequestProcessAccessdirectly insert the PID in theCW_ALLOWED_PIDeBPF HashMap. call it with the pid right after spawning it, or apply it to a process that is already running (Caution, App often scan for GPUs at launch). - Smart Policy: As of 0.12.0, cardwire has its own Application Policy, the SmartPolicy interface lists known applications (
GetAppPolicies), changes their persistent policy (SetAppPolicy) and announces discoveries (NewAppAdded).
Introduction
Having an integrated and hybrid mode is good, but what if we could have the best of both worlds?
This is what cardwire’s smart mode was made for. Cardwire uses a mix of kernel-space + userspace to directly allow processes on the fly.
Kernel-Space
Using the eBPF program and the tracepoint/sched/sched_process_exec hooks, the kernel program notifies cardwired when a new process is executed, sending its pid using the CW_EXEC_EVENTS RING_BUF (in Smart and Manual modes). Once the process is received by cardwired, it will be analyzed in real-time and its pid will be inserted into the CW_ALLOWED_PID map (value always 0) or the CW_FORCED_PID map (value is the GPU id)
When a process exits, the kernel’s tracepoint/sched/sched_process_exit removes the pid from both maps directly, preventing the maps from overflowing.
Userspace
It is responsible for making the actual decisions about whether a process is allowed to use a GPU. It is divided into three main components:
CardwireAnalyzer: A dedicated background task that listens to theCW_EXEC_EVENTSring buffer (and theCW_REPORT_EVENTSring for blocked-access logging). When it receives a new PID from the kernel eBPF, it invokes the analysis helpers. If the application passes, it populates theCW_ALLOWED_PIDmap (value always0) or theCW_FORCED_PIDmap (value is the GPU id).dynamic_analysis.rs: A set of helper functions used to analyze a process in real-time. By reading/proc/<pid>/environand/proc/<pid>/cmdline, it checks for explicitly requested GPUs (likeCARDWIRE_ALLOW=1,CARDWIRE_FORCE_DGPU=1,CARDWIRE_FORCE_GPU=<gpu_id>) or Steam games (SteamAppId), more to be added.static_analysis.rs: A set of helper functions that analyze system data when the daemon starts. It scans the XDG data directories and watches them with inotify so new apps are picked up at install time. Every discovered app is blocked by default until the user allows it (will be changed in 0.13.0, with a toggleable setting).
Notes
Technically, it’s a pure race condition between the cardwire analyzer and the process, cardwire scans and allow a process in ~60-100 microseconds, from my testing, no process initialized its render before cardwire allowed it
Complete Execution Flow
Here is a comprehensive breakdown of how the Kernel and Userspace interact in real-time when an application launches: (Please zoom on it)
sequenceDiagram
participant Proc as Process
participant Kernel as eBPF Kernel Hooks
participant Map as BPF Maps
participant Daemon as CardwireAnalyzer (Userspace)
Note over Proc,Daemon: 1. Process Launch
Proc->>Kernel: sched_process_exec
Kernel->>Map: Send PID via cw_exec_events (RingBuf)
Map->Daemon: Listen to cw_exec_events and wait for new events
Note over Daemon: 2. Real-time Analysis
Daemon->>Daemon: Read /proc/<pid>/environ & cmdline
Daemon->>Daemon: Check CARDWIRE_* env vars, Steam, XDG lists, SQLite policies
alt Is Allowed?
Daemon->>Map: Insert PID into cw_allowed_pid
else Is Forced?
Daemon->>Map: Insert PID into cw_forced_pid with the GPU id
else Not Allowed
Daemon->>Daemon: Do nothing
end
Note over Proc,Kernel: 3. GPU Access & Directory Listing
Proc->>Kernel: getdents64 / file_open (/dev/dri/)
Kernel->>Map: Check cw_allowed_pid and cw_forced_pid
alt PID not in any map
Kernel-->>Proc: hide GPU (Return -ENOENT)
Kernel->>Daemon: Send block event (cw_report_events)
else PID in cw_allowed_pid
Kernel-->>Proc: Allow dGPU and iGPU
else PID in cw_forced_pid (value = GPU id)
Kernel-->>Proc: Allow the forced GPU, hide the others (-ENOENT)
end
Note over Proc,Daemon: 4. Application Exit
Proc->>Kernel: sched_process_exit
Kernel->>Kernel: Remove PID from cw_allowed_pid and cw_forced_pid
Application policies
Smart mode is only available on laptops (SystemType::Laptop). Per-application policies are stored in the app_policies table of the daemon’s SQLite database, with two values: Blocked and Allowed. Known apps are blocked by default until the user allows them, and newly discovered apps are announced through the NewAppAdded D-Bus signal.
The Forced policy will be added in 0.13.0
The policy for a process can be overridden at runtime through the org.opengamingcollective.cardwire.SmartPolicy D-Bus interface (RequestProcessAccess, GetProcessStatus, GetAppPolicies, SetAppPolicy). Note that GetProcessStatus returns an empty string (not "Default") for unclassified processes.
Force_GPU can be used on all systems with the Manual mode.
Building and Development
Building and Development
Using Nix
# Enter development shell
nix develop
# Build the project
nix build
# Run formatting checks
nix build .#checks.x86_64-linux.pre-commit-check
# Run integration tests in VM
nix build .#checks.x86_64-linux.vm-ci-2gpu
nix build .#checks.x86_64-linux.vm-ci-3gpu
nix build .#checks.x86_64-linux.vm-ci-15gpu
# Build the vm and enter
nix run .#nixosConfigurations.x86_64-linux.config.system.build.vm
Manual Compilation
If you don’t use Nix, ensure you have clang, libbpf (devel), libudev (devel), pkg-config and cargo installed (needed for eBPF compilation during the Rust build), plus bpf-linker and a pinned nightly toolchain (see cardwire-ebpf-userspace/build.rs). The GUI build additionally needs the Vulkan, EGL, Wayland and X11 development packages.
Formatting requires nightly rustfmt (the project uses nightly-only formatting options). Install it and run with:
rustup toolchain install nightly --component rustfmt
cargo +nightly fmt --all --check
# Build the project
make
# Install binaries, systemd service, D-Bus config, desktop file, icons and
# metainfo, and enable the systemd unit (requires sudo)
sudo make install
Project Structure
crates/cardwire-cli: User CLI to interact with the daemoncrates/cardwire-daemon: System daemon managing state and D-Bus communicationcrates/cardwire-ebpf: BPF program and LSM hooks (never built directly, built by ebpf-userspace)crates/cardwire-ebpf-userspace: Loads the BPF program, compiles it at build timecrates/cardwire-gui: The iced GUI and tray