Skip to content

Repository files navigation

tkbar

github release ci status stars

A minimalist, hardened status bar for Wayland.

tkbar is small and opinionated on purpose: every optional piece is feature-gated so it can be compiled out, and what doesn't exist is hardcoded by design. A single TOML file tunes the layout and behaviour, a CSS file can restyle everything, and the rest is baked in. Want to go deeper? Fork it, or open a PR with proper feature gating (See CONTRIBUTING.md) .

✨ Features

  • 🖥️ Workspace compositorsniri (default), Hyprland, and sway, selected at build time via Cargo features.
  • 🧩 Components — clickable workspaces, battery, Wi-Fi (SSID & signal), brightness, volume, clock, spacer and a logo glyph.
  • 📐 Any edge — vertical (left/right) or horizontal (top/bottom) bar, with adjustable thickness.
  • 🎨 Themes — ten compiled-in color themes, plus an optional user CSS file that overrides the base stylesheet.
  • ⚙️ Optional configuration — TOML and CSS live behind the config feature, build with --no-default-features and no parser is linked at all.
  • 🔒 Hardened — no unsafe, no network code, no dynamic loading, no panics on external data, and a minimal, auditable dependency tree (see Security).
  • 💻 CLI — optional clap feature gate provides --help, --version, and --config <path> flags for overriding the configuration file path at runtime.
  • 🚧 Coming soon — optional logging (the log crate) feature gate, for people who want more batteries included.

📦 Dependencies

The bar aims for a minimal dependency tree: every crate and library is code that runs with your full user privileges, so only what is strictly needed is pulled in. There is currently no logging framework (just eprintln!), and config parsing is feature-gated so it can be dropped entirely.

Build-time

Dependency Notes
Rust (edition 2024) stable toolchain for builds; nightly only in the devshell for rustfmt/clippy
GTK4 >= 4.12 C library, resolved through pkg-config
gtk4-layer-shell >= 1.0 C library implementing the layer-shell protocol
glib comes with GTK4

With the default config feature, three direct Rust crates are added: directories, serde, toml. Of these, only serde is already present transitively via the default niri backend (pulled in by niri-ipc), so it adds no new transitive code. directories and toml are genuinely new dependencies, and toml in turn pulls in its own small tree. If you build with the hyprland backend instead of niri, serde is also a new dependency. The sway backend pulls in serde, serde_json, and thiserror (via swayipc/swayipc-types). Build with --no-default-features to drop the config crates entirely: no TOML parser is then linked at all.

Run-time

Dependency How it is used Trust level
GTK4 / Pango / Cairo / FreeType linked, renders everything large audited C codebase, keep it updated
gtk4-layer-shell linked, positions the window small C library
a Wayland compositor (niri, Hyprland, or sway) Wayland protocol fully trusted, see SECURITY.md
the compositor's IPC (niri IPC / Hyprland IPC / sway IPC) Unix socket, workspace list/buttons trusted (it is the compositor)
wpctl (WirePlumber) spawned to get/set volume and mute local daemon client, output parsed defensively
nl80211 (neli-wifi) kernel netlink socket, reads Wi-Fi SSID/signal linked, carries untrusted data (SSID)
sysfs (/sys/class/backlight, /sys/class/power_supply) read directly; backlight also written directly (needs group write access, see the NixOS module) kernel-provided

All spawned tools are looked up in PATH. The Nix package wraps the binary so that PATH resolves them from pinned, absolute /nix/store paths.

❄️ NixOS module

The flake ships a NixOS module (nixosModules.default) that installs the bar and can grant backlight write access without any setuid binary or external tool:

{
  imports = [ tkbar.nixosModules.default ];

  programs.tkbar = {
    enable = true;
    backlight = {
      enable = true;        # udev rule for /sys/class/backlight/*/brightness
      users = [ "alice" ];  # members of the backlight group
      group = "video";    # or reuse the conventional video group
    };
  };
}

With backlight.enable, a udev rule gives the tkbar-backlight group (default) write access to /sys/class/backlight/*/brightness, and the bar writes sysfs directly. On an already-booted system, apply it after nixos-rebuild switch with sudo udevadm trigger --subsystem-match=backlight --action=add. See docs/CONFIGURATION.md for all module options.

⚙️ Configuration

Optional and strictly validated: unknown keys are rejected, and a missing file falls back to the hardcoded default. See docs/CONFIGURATION.md for the full TOML format, the optional CSS overloading, and how to select a theme or drop the config feature from Nix.

💻 Usage

When built with the cli feature (enabled by default):

tkbar [OPTIONS]
Flag Description
--help Print help information
--version Print version
--config <PATH> Path to configuration file (requires the config feature)

Example:

tkbar --config ~/.config/tkbar/alt.toml

The --config flag overrides the default $XDG_CONFIG_HOME/tkbar/config.toml path for that invocation only.

🔒 Security

A status bar runs unsandboxed with your full user privileges, so attack surface is taken seriously: minimal dependencies, no unsafe, no panics on external data, no network code, no dynamic loading, and a pinned, reproducible build.

See docs/SECURITY.md for the full threat model, the enforced security properties, and how to report a vulnerability.

🌱 Origin

I was unsatisfied with the state of Wayland bars and shells (bloat, huge attack surface, not enough config options, protocols left unhandled), so I wrote a minimal thing that worked for me. It has since grown into a bar meant to work for anyone: multiple compositor backends, themes, Nix packaging, and a documented security model, without giving up on minimalism.

About

tkbar ─ A minimalist, hardened status bar.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages