mirror of github.com/Breadway/breadmon
  • Rust 98.7%
  • Shell 1.3%
Find a file
2026-10-14 10:31:39 +08:00
.forgejo/workflows docs: deprecate breadmon and retire release jobs 2026-10-01 15:45:27 +08:00
ci ci: make the bread-ecosystem clone in ci/build.sh race-free 2026-09-29 17:23:41 +08:00
src fix(monitor): pre-create fake-hyprctl scripts to stop ETXTBSY flakes 2026-10-14 08:57:20 +08:00
.gitignore ci: build dev track and PR checks against dependency main 2026-09-28 06:42:45 +08:00
AGENTS.md docs: deprecate breadmon and retire release jobs 2026-10-01 15:45:27 +08:00
Cargo.lock chore: bump version to 0.1.5 2026-09-11 19:08:49 +08:00
Cargo.toml chore: bump version to 0.1.5 2026-09-11 19:08:49 +08:00
CONTRIBUTING.md docs: deprecate breadmon and retire release jobs 2026-10-01 15:45:27 +08:00
EVENTS.md docs: remove em dashes from code and docs 2026-09-09 13:59:45 +08:00
LICENSE Initial commit 2026-07-02 20:59:16 +08:00
README.md fix(monitor): switch monitors off through hyprctl eval and check the reply (MON-14) 2026-10-09 16:11:47 +08:00

breadmon

Deprecated. Breadmon is no longer shipped with BOS or listed in bakery. Use the Displays page in bos-settings for monitor layout, resolution, scale, and rotation. Existing installs can be removed with bakery remove breadmon; saved profiles under ~/.config/breadmon/profiles/ are preserved.

A terminal UI monitor manager for Hyprland. Lets you position, configure, and mirror displays interactively, then apply a live layout on Hyprland configured with hyprland.lua (as on BOS).

The Display panel in bos-settings (GUI) and breadmon (TUI) share ~/.config/hypr/monitors.json, the layout Hyprland reads at login/reload. Applying in breadmon writes that file so the settings app and the next session stay in sync. Named profiles remain optional snapshots under ~/.config/breadmon/profiles/.

Requirements

  • Hyprland configured with hyprland.lua (as on BOS (Bread OS)) for live apply. The a key runs hyprctl eval 'hl.monitor({...})', and switches monitors off with hyprctl eval "hl.dispatch(hl.dsp.dpms({ action = 'off', monitor = '<name>' }))". Hyprland configured with hyprland.conf has no eval request, so apply will fail there with an explicit error instead of the raw hyprctl response. Viewing, arranging, and saving profiles work with either configuration; only live apply needs hyprland.lua.
  • The hyprctl binary must be on PATH
  • Rust toolchain (to build from source)

Build from source

The last released version is 0.1.5. To build from source:

cargo build --release

The binary is written to target/release/breadmon.

Usage

breadmon

The TUI opens with four tabs, switchable by number key or mouse click:

Key Tab
1 / F1 Layout
2 / F2 Config
3 / F3 Mirror
4 / F4 Profiles

Layout

A scaled canvas showing all connected monitors. The selected monitor is highlighted.

Key Action
hjkl / arrow keys Move selected monitor 1 px
Shift+hjkl Move selected monitor 10 px
Tab / n Cycle to next monitor
Shift+Tab / p Cycle to previous monitor
0 Auto-arrange monitors left-to-right with no gaps
[ / ] Zoom canvas out / in
Mouse drag Drag monitor to reposition

Monitors snap to each other's edges when dragged or nudged within 10 px.

Config

Per-monitor settings for the currently selected display.

Key Action
jk / Tab Move between fields
hl / scroll Cycle field value
, / . Scale −0.1 / +0.1
[ / ] Switch to previous / next monitor
Enter Commit scale edit and apply
Esc Discard pending edits

Fields: Resolution, Refresh rate, Scale, Transform (rotation/flip), VRR, DPMS, Mirror of.

The header shows the monitor's PPI and a suggested fractional scale when physical dimensions are available.

Mirror

Finds the best common mode between two monitors and sets one to mirror the other. Use Tab to move focus between source and target, hl to cycle the selection, Enter to confirm.

Profiles

Named snapshots of the current monitor configuration, stored as TOML files. Loading a profile updates the TUI; applying it (a) also writes monitors.json.

Key Action
jk Navigate profile list
Enter Load selected profile
d d Delete selected profile (double-press within 3 s)
Tab Move focus to name input / save button

Profiles are saved to ~/.config/breadmon/profiles/.

Global keys

Key Action
a Apply current configuration via hyprctl eval 'hl.monitor({...})' (needs Hyprland configured with hyprland.lua) and write ~/.config/hypr/monitors.json
s Write ~/.config/hypr/monitors.json without a live apply
r Refresh monitor list from Hyprland
Ctrl+Z Undo last change (up to 20 steps)
q / Ctrl+C Quit (prompts once if there are unsaved changes)

breadmon also listens on Hyprland's event socket and reloads the monitor list automatically when a display is connected or disconnected.

Config

Shared store: ~/.config/hypr/monitors.json, the same file the bos-settings Display panel edits and Hyprland applies on login/reload. breadmon is the TUI; Display is the GUI. Schema:

{
  "monitors": [
    { "output": "", "mode": "preferred", "position": "auto", "scale": "auto", "mirror": "<optional string>" }
  ]
}

Empty output is the wildcard default (any connector). breadmon loads this file on start (overlaid onto the live hyprctl list) and writes it (pretty JSON) after a successful apply, and when you press s.

Named snapshots: plain TOML under ~/.config/breadmon/profiles/. Each file records the monitor name, mode, position, scale, transform, VRR, DPMS, and mirror source. They are created and managed through the Profiles tab. Applying a profile writes monitors.json so Hyprland and Display stay in sync.

bread event integration

breadmon works the same with or without breadd. After a successful live apply (hyprctl eval 'hl.monitor({...})' on Hyprland configured with hyprland.lua, not the bos-settings Display panel), it publishes bread.mon.applied. If breadd is down, the emit is a silent no-op; apply itself is unchanged. See EVENTS.md for the bus contract. bread is not a bakery dependency.