Files
quickshell_bar/CLAUDE.md
2026-05-31 09:28:44 +02:00

4.5 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

A Wayland status bar for Sway/i3, written entirely in QML and driven by Quickshell, packaged with a Nix flake.

Commands

# run without building (hot-reloads on file save)
nix develop          # shell with quickshell + qmlls/qmlformat on PATH
quickshell --path .  # or: qs -p .

nix run .            # run straight from the flake
nix build . && ./result/bin/quickshell-bar   # build the wrapper, then run

There is no test suite, no linter, and no build step for the QML itself — it's interpreted and hot-reloaded. The only "build" is the Nix wrapper that pins fonts and runtime tools. qmlformat/qmlls (from qt6.qtdeclarative, available in the dev shell) are the only static tooling. Verify changes by running the bar and looking at it.

Architecture

Entry point. shell.qmlShellRoot with Variants { model: Quickshell.screens } spawns one widgets/Bar.qml (PanelWindow) per monitor. Bar.qml is a fixed three-zone layout: workspaces (left), clock (center), a RowLayout of metric modules (right). Changing module order/presence is purely editing that RowLayout.

Three import roots, registered via qmldir:

  • config/Theme and Icons, both singletons (pragma Singleton + singleton line in config/qmldir). Global palette/geometry/fonts and Nerd Font glyphs. Import with import "../config", reference as Theme.x / Icons.x.
  • services/SysStats, a singleton that is the single source of truth for all /proc + /sys metrics. Import with import "../services".
  • widgets/ — the visual modules. Pill.qml is the rounded container every module reuses (default property alias content lets children sit inside a centered RowLayout); MetricPill.qml adds the icon + value convention.

The metrics pipeline (services/SysStats.qml) is the core design. One Timer (1 Hz, interval property) calls _tickOnce(), which reload()s a set of FileViews and parses them into reactive properties (cpu, cpuFreq, mem, temp, rates, battery, …). Widgets just bind to those properties. Key conventions:

  • FileView { blockLoading: true } makes reload() synchronous so text() is fresh on the same tick. Use this for tiny virtual files in /proc//sys.
  • Add a metric by: declaring a property, adding a FileView (or reusing one by reassigning its path, as _parseNet does for the active interface), writing a _parseX(), and calling reload() + _parseX() inside _tickOnce().
  • Deltas (CPU%, net rates) keep a _prev* field and diff against the last tick.
  • Two metrics escape the pure-virtual-file rule: disk usage runs df via a Process only every 30 ticks (_tick % 30), and a one-shot Process runs services/discover.sh at startup. The bar avoids per-tick subprocess spawns by design — keep new metrics reading virtual files, not shelling out.

discover.sh handshake. At startup it prints TEMP <path> and BAT <path> (hwmon temp sensor + main battery, skipping scope=Device peripherals) on stdout; the QML side parses those lines into tempPath/batPath, which then feed FileViews. sysfs paths are stable for a boot, so this runs once, not per tick.

Conventions & gotchas

  • Icons are referenced by Unicode codepoint (config/Icons.qml, String.fromCharCode(0x...)) so source stays ASCII. The glyph must exist in the bundled Nerd Fontflake.nix bundles nerd-fonts.jetbrains-mono + nerd-fonts.symbols-only (Font Awesome 4 range, plus Material Design). Font Awesome 5+ codepoints are NOT present and render as tofu squares; verify a codepoint is covered before using it. Codepoints above 0xFFFF (e.g. Material Design 0xf0xxx) need String.fromCodePoint, not String.fromCharCode.
  • Fonts are pinned via FONTCONFIG_FILE in the flake wrapper, so glyphs render regardless of the host's installed fonts. Adding a font means editing fontsConf in flake.nix.
  • Bar.qml remaps its layer surface on geometry change (geomKey → toggle visible). This is a deliberate workaround for stale-buffer garbage after output rotation/transform under Sway — don't remove it.
  • Quickshell upstream is tracked directly in flake.nix (git, not nixpkgs) to pick up layer-surface fixes ahead of release.
  • Native Quickshell services back some modules: Quickshell.I3 (workspaces), Quickshell.Services.SystemTray (tray), PipeWire (volume).